[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:
kobalicek
2023-09-10 00:09:34 +02:00
parent 8e2f4de484
commit e4e61c4f15
60 changed files with 28000 additions and 10671 deletions

3
.gitignore vendored
View File

@@ -1,6 +1,3 @@
/build
/build_*
/tools/asmdb
.vscode
.kdev4
*.kdev4

View File

@@ -55,10 +55,6 @@ if (NOT DEFINED ASMJIT_NO_X86)
set(ASMJIT_NO_X86 FALSE)
endif()
if (NOT DEFINED ASMJIT_NO_AARCH32)
set(ASMJIT_NO_AARCH32 FALSE)
endif()
if (NOT DEFINED ASMJIT_NO_AARCH64)
set(ASMJIT_NO_AARCH64 FALSE)
endif()
@@ -86,7 +82,6 @@ set(ASMJIT_EMBED "${ASMJIT_EMBED}" CACHE BOOL "Embed 'asmjit
set(ASMJIT_STATIC "${ASMJIT_STATIC}" CACHE BOOL "Build 'asmjit' library as static")
set(ASMJIT_SANITIZE "${ASMJIT_SANITIZE}" CACHE STRING "Build with sanitizers: 'address', 'undefined', etc...")
set(ASMJIT_NO_X86 "${ASMJIT_NO_X86}" CACHE BOOL "Disable X86/X64 backend")
set(ASMJIT_NO_AARCH32 "${ASMJIT_NO_AARCH32}" CACHE BOOL "Disable AArch32 backend (ARM and THUMB)")
set(ASMJIT_NO_AARCH64 "${ASMJIT_NO_AARCH64}" CACHE BOOL "Disable AArch64 backend")
set(ASMJIT_NO_FOREIGN "${ASMJIT_NO_FOREIGN}" CACHE BOOL "Disable all foreign architectures (enables only a native architecture)")
set(ASMJIT_NO_NATVIS "${ASMJIT_NO_NATVIS}" CACHE BOOL "Disable natvis support (embedding asmjit.natvis in PDB)")
@@ -274,7 +269,6 @@ endif()
foreach(build_option ASMJIT_STATIC
# AsmJit backends selection.
ASMJIT_NO_X86
ASMJIT_NO_AARCH32
ASMJIT_NO_AARCH64
ASMJIT_NO_FOREIGN
# AsmJit features selection.
@@ -396,11 +390,13 @@ set(ASMJIT_SRC_LIST
asmjit/core/zonevector.cpp
asmjit/core/zonevector.h
asmjit/a64.h
asmjit/arm.h
asmjit/arm/armformatter.cpp
asmjit/arm/armformatter_p.h
asmjit/arm/armglobals.h
asmjit/arm/armoperand.h
asmjit/arm/armutils.h
asmjit/arm/a64archtraits_p.h
asmjit/arm/a64assembler.cpp
asmjit/arm/a64assembler.h
@@ -424,7 +420,6 @@ set(ASMJIT_SRC_LIST
asmjit/arm/a64operand.h
asmjit/arm/a64rapass.cpp
asmjit/arm/a64rapass_p.h
asmjit/arm/a64utils.h
asmjit/x86.h
asmjit/x86/x86archtraits_p.h

View File

@@ -45,8 +45,6 @@ Project Organization
TODO
----
* [ ] Core:
* [ ] Add support for user external buffers in CodeBuffer / CodeHolder.
* [ ] Ports:
* [ ] 32-bit ARM/Thumb port.
* [ ] 64-bit ARM (AArch64) port.

15
db/README.md Normal file
View File

@@ -0,0 +1,15 @@
AsmJit Instruction Database
---------------------------
This is a database of instructions that is used by AsmJit to generate its internal database and also assembler implementations. This project started initially as AsmDB, but was merged to AsmJit later to make the maintenance easier. The database was created in a way so that each instruction definition would only need a single line in JSON data. The data is then processed by architecture specific data readers that make the data canonical and ready for processing.
AsmJit database provides the following ISAs:
* `isa_x86.json` - provides X86 instruction data (both 32-bit and 64-bit)
* `isa_arm.json` - provides AArch32 instruction data (both ARM32 and THUMB)
* `isa_a64.json` - provides AArch64 instruction data
To Be Documented
----------------
This project will be refactored and documented in the future.

921
db/aarch64.js Normal file
View File

@@ -0,0 +1,921 @@
// 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
(function($scope, $as) {
"use strict";
function FAIL(msg) { throw new Error("[AArch64] " + msg); }
// Import
// ======
const base = $scope.base ? $scope.base : require("./base.js");
const exp = $scope.exp ? $scope.exp : require("./exp.js")
const hasOwn = Object.prototype.hasOwnProperty;
const dict = base.dict;
const NONE = base.NONE;
const Parsing = base.Parsing;
const MapUtils = base.MapUtils;
// Export
// ======
const arm = $scope[$as] = dict();
// Database
// ========
arm.dbName = "isa_aarch64.json";
// asmdb.aarch64.Utils
// ===================
// Can be used to assign the number of bits each part of the opcode occupies.
// NOTE: THUMB instructions that use halfword must always specify the width
// of all registers as many instructictions accept only LO (r0..r7) registers.
const FieldInfo = {
"P" : { "bits": 1 },
"U" : { "bits": 1 },
"W" : { "bits": 1 },
"S" : { "bits": 1 },
"R" : { "bits": 1 },
"H" : { "bits": 1 },
"F" : { "bits": 1 },
"post" : { "bits": 1 },
"!post" : { "bits": 1 },
"op" : { "bits": 1 }, // TODO: This should be fixed.
"s" : { "bits": 1 },
"sz" : { "bits": 2 },
"msz" : { "bits": 2 },
"sop" : { "bits": 2 },
"cond" : { "bits": 4 },
"nzcv" : { "bits": 4 },
"cmode" : { "bits": 4 },
"CRn" : { "bits": 4 },
"CRm" : { "bits": 4 },
"Rx" : { "bits": 5, "read": true , "write": true },
"Rx2" : { "bits": 5, "read": true , "write": true },
"Rdn" : { "bits": 5, "read": true , "write": true },
"Rd" : { "bits": 5, "read": false, "write": true },
"Rd2" : { "bits": 5, "read": false, "write": true },
"Rs" : { "bits": 5, "read": true , "write": false },
"Rs2" : { "bits": 5, "read": true , "write": false },
"Rn" : { "bits": 5, "read": true , "write": false },
"Rm" : { "bits": 5, "read": true , "write": false },
"Ra" : { "bits": 5, "read": true , "write": false },
"Rt" : { "bits": 5, "read": true , "write": false },
"Rt2" : { "bits": 5, "read": true , "write": false },
"Wx" : { "bits": 5, "read": true , "write": true },
"Wx2" : { "bits": 5, "read": true , "write": true },
"Wdn" : { "bits": 5, "read": true , "write": true },
"Wd" : { "bits": 5, "read": false, "write": true },
"Wd2" : { "bits": 5, "read": false, "write": true },
"Ws" : { "bits": 5, "read": true , "write": false },
"Ws2" : { "bits": 5, "read": true , "write": false },
"Wn" : { "bits": 5, "read": true , "write": false },
"Wm" : { "bits": 5, "read": true , "write": false },
"Wa" : { "bits": 5, "read": true , "write": false },
"Wt" : { "bits": 5, "read": true , "write": false },
"Wt2" : { "bits": 5, "read": true , "write": false },
"Xx" : { "bits": 5, "read": true , "write": true },
"Xx2" : { "bits": 5, "read": true , "write": true },
"Xdn" : { "bits": 5, "read": true , "write": true },
"Xd" : { "bits": 5, "read": false, "write": true },
"Xd2" : { "bits": 5, "read": false, "write": true },
"Xs" : { "bits": 5, "read": true , "write": false },
"Xs2" : { "bits": 5, "read": true , "write": false },
"Xn" : { "bits": 5, "read": true , "write": false },
"Xm" : { "bits": 5, "read": true , "write": false },
"Xa" : { "bits": 5, "read": true , "write": false },
"Xt" : { "bits": 5, "read": true , "write": false },
"Xt2" : { "bits": 5, "read": true , "write": false },
"Bx" : { "bits": 5, "read": true , "write": true },
"Bx2" : { "bits": 5, "read": true , "write": true },
"Bdn" : { "bits": 5, "read": true , "write": true },
"Bd" : { "bits": 5, "read": false, "write": true },
"Bd2" : { "bits": 5, "read": false, "write": true },
"Bs" : { "bits": 5, "read": true , "write": false },
"Bs2" : { "bits": 5, "read": true , "write": false },
"Bn" : { "bits": 5, "read": true , "write": false },
"Bm" : { "bits": 5, "read": true , "write": false },
"Ba" : { "bits": 5, "read": true , "write": false },
"Hx" : { "bits": 5, "read": true , "write": true },
"Hx2" : { "bits": 5, "read": true , "write": true },
"Hdn" : { "bits": 5, "read": true , "write": true },
"Hd" : { "bits": 5, "read": false, "write": true },
"Hd2" : { "bits": 5, "read": false, "write": true },
"Hs" : { "bits": 5, "read": true , "write": false },
"Hs2" : { "bits": 5, "read": true , "write": false },
"Hn" : { "bits": 5, "read": true , "write": false },
"Hm" : { "bits": 5, "read": true , "write": false },
"Ha" : { "bits": 5, "read": true , "write": false },
"Sx" : { "bits": 5, "read": true , "write": true },
"Sx2" : { "bits": 5, "read": true , "write": true },
"Sdn" : { "bits": 5, "read": true , "write": true },
"Sd" : { "bits": 5, "read": false, "write": true },
"Sd2" : { "bits": 5, "read": false, "write": true },
"Ss" : { "bits": 5, "read": true , "write": false },
"Ss2" : { "bits": 5, "read": true , "write": false },
"Sn" : { "bits": 5, "read": true , "write": false },
"Sm" : { "bits": 5, "read": true , "write": false },
"Sa" : { "bits": 5, "read": true , "write": false },
"Dx" : { "bits": 5, "read": true , "write": true },
"Dx2" : { "bits": 5, "read": true , "write": true },
"Ddn" : { "bits": 5, "read": true , "write": true },
"Dd" : { "bits": 5, "read": false, "write": true },
"Dd2" : { "bits": 5, "read": false, "write": true },
"Ds" : { "bits": 5, "read": true , "write": false },
"Ds2" : { "bits": 5, "read": true , "write": false },
"Dn" : { "bits": 5, "read": true , "write": false },
"Dn2" : { "bits": 5, "read": true , "write": false },
"Dm" : { "bits": 5, "read": true , "write": false },
"Da" : { "bits": 5, "read": true , "write": false },
"Qx" : { "bits": 5, "read": true , "write": true },
"Qx2" : { "bits": 5, "read": true , "write": true },
"Qdn" : { "bits": 5, "read": true , "write": true },
"Qd" : { "bits": 5, "read": false, "write": true },
"Qd2" : { "bits": 5, "read": false, "write": true },
"Qs" : { "bits": 5, "read": true , "write": false },
"Qs2" : { "bits": 5, "read": true , "write": false },
"Qn" : { "bits": 5, "read": true , "write": false },
"Qn2" : { "bits": 5, "read": true , "write": false },
"Qm" : { "bits": 5, "read": true , "write": false },
"Qa" : { "bits": 5, "read": true , "write": false },
"Vx" : { "bits": 5, "read": true , "write": true },
"Vx2" : { "bits": 5, "read": true , "write": true },
"Vdn" : { "bits": 5, "read": true , "write": true },
"Vd" : { "bits": 5, "read": false, "write": true },
"Vd2" : { "bits": 5, "read": false, "write": true },
"Vs" : { "bits": 5, "read": true , "write": false },
"Vs2" : { "bits": 5, "read": true , "write": false },
"Vn" : { "bits": 5, "read": true , "write": false },
"Vm" : { "bits": 5, "read": true , "write": false },
"Va" : { "bits": 5, "read": true , "write": false },
"Zx" : { "bits": 5, "read": true , "write": true },
"Zx2" : { "bits": 5, "read": true , "write": true },
"Zda" : { "bits": 5, "read": true , "write": true },
"Zdn" : { "bits": 5, "read": true , "write": true },
"Zdn2" : { "bits": 5, "read": true , "write": true },
"Zd" : { "bits": 5, "read": false, "write": true },
"Zd2" : { "bits": 5, "read": false, "write": true },
"Zs" : { "bits": 5, "read": true , "write": false },
"Zs2" : { "bits": 5, "read": true , "write": false },
"Zn" : { "bits": 5, "read": true , "write": false },
"Zm" : { "bits": 5, "read": true , "write": false },
"Zk" : { "bits": 5, "read": true , "write": false },
"Za" : { "bits": 5, "read": true , "write": false },
"Pdn" : { "bits": 4, "read": true , "write": true },
"Pdm" : { "bits": 4, "read": true , "write": true },
"Pd" : { "bits": 4, "read": false, "write": true },
"Ps" : { "bits": 4, "read": true , "write": false },
"Pn" : { "bits": 4, "read": true , "write": false },
"Pm" : { "bits": 4, "read": true , "write": false },
"Pg" : { "bits": 4, "read": true , "write": false }
};
arm.FieldInfo = FieldInfo;
// AArch64 utilities.
class Utils {
static splitInstructionSignature(s) {
const names = s.match(/^[\w\|]+/)[0];
s = s.substring(names.length);
const opOffset = s.indexOf(" ")
const suffix = s.substring(0, opOffset).trim();
const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim();
return {
names: names.split("|").map((base)=>{ return base + suffix}),
operands: operands
}
}
static parseShiftOrExtendOp(s) {
const space = s.indexOf(" ");
if (space === -1)
return "";
const ops = s.substring(0, space).trim();
for (let op of ops.split("|"))
if (!/^(sop|extend|lsl|lsr|asr|uxtw|sxtw|sxtx|mul)$/.test(op))
return "";
return ops;
}
}
arm.Utils = Utils;
function normalizeNumber(n) {
return n < 0 ? 0x100000000 + n : n;
}
function decomposeOperand(s) {
let type = null;
let element = null;
let consecutive = 0;
let maskType = "";
const elementM = s.match(/\[#(\w+)\]$/);
if (elementM) {
element = elementM[1];
s = s.substring(0, s.length - elementM[0].length);
}
const typeM = s.match(/\.(\w+)$/);
if (typeM) {
type = typeM[1];
s = s.substring(0, s.length - typeM[0].length);
}
const maskM = s.match(/\/(M|Z|MZ)$/);
if (maskM) {
maskType = maskM[1];
s = s.substring(0, s.length - maskM[0].length);
}
if (s.endsWith("++")) {
consecutive = 2;
s = s.substring(0, s.length - 2);
}
else if (s.endsWith("+")) {
consecutive = 1;
s = s.substring(0, s.length - 1);
}
let m = s.match(/==|\!=|>=|<=|\*/);
let restrict = false;
if (m) {
restrict = s.substring(m.index);
s = s.substring(0, m.index);
}
return {
data : s,
maskType : maskType,
type : type,
element : element,
restrict : restrict,
consecutive: consecutive
};
}
function splitOpcodeFields(s) {
const arr = s.split("|");
const out = [];
for (let i = 0; i < arr.length; i++) {
const val = arr[i];
if (/^[0-1A-Z]{2,}$/.test(val))
out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g));
else
out.push(val);
}
return out.map((field)=>{return field.trim(); });
}
// asmdb.aarch64.Operand
// =====================
// ARM operand.
class Operand extends base.Operand {
constructor(def) {
super(def);
// Register.
this.sp = ""; // GP register stack access: ["", "WSP" or "SP"].
this.mask = ""; // Masking specifier.
}
hasMemModes() {
return Object.keys(this.memModes).length !== 0;
}
get name() {
switch (this.type) {
case "reg": return this.reg;
case "mem": return this.mem;
case "imm": return this.imm;
case "rel": return this.rel;
default : return "";
}
}
get scale() {
if (this.restrict && this.restrict.startsWith("*"))
return parseInt(this.restrict.substring(1), 10);
else
return 0;
}
}
arm.Operand = Operand;
// asmdb.aarch64.Instruction
// =========================
function patternFromOperand(key) { return key; }
// ARM instruction.
class Instruction extends base.Instruction {
constructor(db, data) {
super(db, data);
this.name = data.name;
this.it = dict(); // THUMB's 'it' flags.
this.apsr = dict();
this.fpcsr = dict();
this.calc = dict(); // Calculations required to generate opcode.
this.immCond = []; // Immediate value conditions (array of conditions).
this._assignOperands(data.operands);
this._assignOpcode(data.op);
for (let k in data) {
if (k === "name" || k == "op" || k === "operands")
continue;
this._assignAttribute(k, data[k]);
}
this._updateOperandsInfo();
this._postProcess();
}
_assignAttribute(key, value) {
switch (key) {
case "it":
for (let it of value.split(" "))
this.it[it.trim()] = true;
break;
case "apsr":
case "fpcsr":
this._assignAttributeKeyValue(key, value);
break;
case "imm":
this.imm = exp.parse(value);
break;
case "calc":
for (let calcKey in value)
this.calc[calcKey] = exp.parse(value[calcKey]);
break;
default:
super._assignAttribute(key, value);
}
}
_assignAttributeKeyValue(name, content) {
const attributes = content.trim().split(/[ ]+/);
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i].trim();
if (!attr)
continue;
const eq = attr.indexOf("=");
let key = eq === -1 ? attr : attr.substring(0, eq);
let val = eq === -1 ? true : attr.substring(eq + 1);
// If the key contains "|" it's a definition of multiple attributes.
if (key.indexOf("|") !== -1) {
const dot = key.indexOf(".");
const base = dot === -1 ? "" : key.substring(0, dot + 1);
const keys = (dot === -1 ? key : key.substring(dot + 1)).split("|");
for (let j = 0; j < keys.length; j++)
this[name][base + keys[j]] = val;
}
else {
this[name][key] = val;
}
}
}
_assignOperands(s) {
if (!s) return;
// Split into individual operands and push them to `operands`.
const arr = base.Parsing.splitOperands(s);
for (let i = 0; i < arr.length; i++) {
let def = arr[i].trim();
const op = new Operand(def);
const sp = def.match(/^(\w+)\|(SP|WSP)$/);
if (sp) {
def = sp[1];
op.sp = sp[2];
}
const consecutive = def.match(/(\d+)x\{(.*)\}([+]?[+]?)/);
if (consecutive)
def = consecutive[2];
op.sign = false;
op.element = null;
op.shiftOp = "";
op.shiftImm = null;
op.shiftCond = "";
// Handle {optional} attribute.
if (Parsing.isOptional(def)) {
op.optional = true;
def = Parsing.clearOptional(def);
}
// Handle commutativity <-> symbol.
if (Parsing.isCommutative(def)) {
op.commutative = true;
def = Parsing.clearCommutative(def);
}
// Handle shift operation.
let shiftOp = Utils.parseShiftOrExtendOp(def);
if (shiftOp) {
op.shiftOp = shiftOp;
def = def.substring(shiftOp.length + 1);
}
if (def.startsWith("[")) {
op.type = "mem";
op.memModes = dict();
op.base = null;
op.index = null;
op.offset = null;
let mem = def;
let didHaveMemMode = false;
for (;;) {
if (mem.endsWith("!")) {
op.memModes.preIndex = true;
mem = mem.substring(0, mem.length - 1);
didHaveMemMode = true;
break;
}
if (mem.endsWith("@")) {
op.memModes.postIndex = true;
mem = mem.substring(0, mem.length - 1);
didHaveMemMode = true;
break;
}
if (mem.endsWith("{!}")) {
op.memModes.offset = true;
op.memModes.preIndex = true;
mem = mem.substring(0, mem.length - 3);
didHaveMemMode = true;
continue;
}
if (mem.endsWith("{@}")) {
op.memModes.offset = true;
op.memModes.postIndex = true;
mem = mem.substring(0, mem.length - 3);
didHaveMemMode = true;
continue;
}
break;
}
if (!mem.endsWith("]"))
FAIL(`Unknown memory operand '${mem}' in '${def}'`);
let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() });
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const m = part.match(/^\{(([a-z]+)(\|[a-z]+)*)\s+#(\w+)\s*(\*\s*\d+\s*)?\}$/);
if (m) {
op.shiftOp = m[1];
op.shiftImm = m[2];
if (m[3])
op.shiftCond = m[3]
continue;
}
if (i === 0) {
op.base = dict();
op.base.field = part;
op.base.exp = null;
const m = part.match(/^([A-Za-z]\w*(?:\.\w+)?)/);
if (m && m[1].length < part.length) {
op.base.exp = exp.parse(part);
op.base.field = m[1];
}
}
else if (part.startsWith("#")) {
let p = part.substring(1);
let u = "1";
let offExp = null;
let offMul = 1;
if (p.startsWith("+/-")) {
u = "U";
p = p.substring(3);
}
const expMatch = p.match(/^([A-Za-z]\w*)==/);
if (expMatch) {
offExp = exp.parse(p);
p = p.substring(0, expMatch[1].length);
}
const mulMatch = p.match(/\s*\*\s*(\d+)$/);
if (mulMatch) {
offMul = parseInt(mulMatch[1]);
p = p.substring(0, mulMatch.index);
}
op.offset = dict();
op.offset.field = p;
op.offset.u = u;
op.offset.exp = offExp;
op.offset.mul = offMul;
}
else {
let p = part;
let u = "1";
if (p.startsWith("+/-")) {
u = "U";
p = p.substring(3);
}
op.index = dict();
op.index.field = p;
op.index.u = u;
const m = p.match(/^([A-Za-z\|]\w*(?:\.\w+)?)/);
if (m && m[1].length < p.length) {
op.index.exp = exp.parse(p);
op.index.field = m[1];
}
}
}
if (!op.hasMemModes() && (op.offset || op.index))
op.memModes.offset = true;
op.mem = mem;
}
else if (def.startsWith("#")) {
const obj = decomposeOperand(def);
const imm = obj.data;
op.type = "imm";
op.imm = imm.substring(1); // Immediate operand name.
op.immSize = 0; // Immediate size in bits.
op.restrict = obj.restrict; // Immediate condition.
}
else {
// Some instructions use Reg! to specify that the register increments.
if (def.endsWith("!")) {
def = def.substring(0, def.length - 1)
op.regInc = true
}
const obj = decomposeOperand(def);
const reg = obj.data;
const type = reg.substring(0, 1).toLowerCase();
const info = FieldInfo[reg];
if (!info)
FAIL(`Unknown register operand '${reg}' in '${def}'`);
op.type = info.list ? "reg-list" : "reg";
op.reg = reg; // Register name (as specified in manual).
op.regType = type; // Register type.
op.regList = !!info.list; // Register list.
op.maskType = obj.maskType; // Mask type.
op.elementType = obj.type // Element type or t, ta, tb.
op.read = info.read; // Register access (read).
op.write = info.write; // Register access (write).
op.element = obj.element; // Register element[] access.
op.restrict = obj.restrict; // Register condition.
op.consecutive = obj.consecutive;
}
this.operands.push(op);
if (consecutive) {
const count = parseInt(consecutive[1]);
for (let n = 2; n <= count; n++) {
const def = consecutive[3].replace(op.reg, op.reg + n);
const opN = new Operand(def);
opN.type = "reg";
opN.reg = op.reg + n;
opN.regType = op.regType;
opN.read = op.read;
opN.write = op.write;
opN.element = op.element;
opN.consecutive = consecutive[3].length;
opN.artificial = true;
this.operands.push(opN);
}
}
}
}
_assignOpcode(s) {
this.opcodeString = s;
let opcodeIndex = 0;
let opcodeValue = 0;
let patternMap = {};
// Split opcode into its fields.
const arr = splitOpcodeFields(s);
const dup = dict();
const fields = this.fields;
const pattern = [];
const fieldMap = Object.create(null);
for (let field of arr) {
fieldMap[field] = true;
}
for (let i = arr.length - 1; i >= 0; i--) {
let key = arr[i].trim();
let m;
if (/^[0-1]+$/.test(key)) {
// This part of the opcode is RAW bits, they contribute to the `opcodeValue`.
opcodeValue |= parseInt(key, 2) << opcodeIndex;
opcodeIndex += key.length;
pattern.unshift("_".repeat(key.length));
}
else {
pattern.unshift(patternFromOperand(key));
patternMap[patternFromOperand(key)] = true;
let size = 0;
let mask = 0;
let bits = 0;
let from = -1;
let lbit = key.startsWith("'");
let hbit = key.endsWith("'");
if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) {
const a = parseInt(m[1], 10);
const b = parseInt(m[2], 10);
if (a < b)
FAIL(`Invalid bit range '${key}' in opcode '${s}'`);
from = b;
size = a - b + 1;
mask = ((1 << size) - 1) << b;
key = key.substring(0, m.index).trim();
}
else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) {
from = parseInt(m[1], 10);
size = 1;
mask = 1 << from;
key = key.substring(0, m.index).trim();
}
else if ((m = key.match(/\:\s*(\d+)$/))) {
size = parseInt(m[1], 10);
bits = size;
key = key.substring(0, m.index).trim();
}
else {
const key_ = key;
if (lbit || hbit) {
from = 0;
if (lbit && hbit)
FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`);
if (lbit) {
key = key.substring(1);
}
if (hbit) {
key = key.substring(0, key.length - 1);
from = 4;
}
size = 1;
}
else if (FieldInfo[key]) {
// Sizes of some standard fields can be assigned automatically.
size = FieldInfo[key].bits;
bits = size;
if (fieldMap["'" + key])
from = 1;
}
else if (key.length === 1) {
// Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified.
size = 1;
bits = 1;
}
else {
FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`);
}
if (dup[key_] === true) {
bits = 0;
lbit = 0;
hbit = 0;
}
else {
dup[key_] = true;
}
}
let field = fields[key];
if (!field) {
field = {
index: opcodeIndex,
values: [],
bits: 0,
mask: 0,
lbit: 0,
hbit: 0 // Only 1 if a single quote (') was used.
}
fields[key] = field;
}
if (from === -1)
from = field.bits;
field.mask |= mask;
field.bits += bits;
field.lbit += lbit;
field.hbit += hbit;
field.values.push({
index: opcodeIndex,
from: from,
size: size
});
opcodeIndex += size;
}
}
for (let i = 0; i < pattern.length; i++)
if (pattern[i] === 'U')
pattern[i] = "_";
// Normalize all fields.
for (let key in fields) {
const field = fields[key];
// There should be either number of bits or mask, there shouldn't be both.
if (!field.bits && !field.mask)
FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`);
if (field.bits && field.mask)
FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`);
if (field.bits)
field.mask = ((1 << field.bits) - 1);
else if (field.mask)
field.bits = 32 - Math.clz32(field.mask);
// Handle field that used single-quote.
if (field.lbit) {
field.mask = (field.mask << 1) | 0x1;
field.bits++;
}
if (field.hbit) {
field.mask |= 1 << field.bits;
field.bits++;
}
const op = this.operandByName(key);
if (op && op.isImm())
op.immSize = field.bits;
}
// Check if the opcode value has the correct number of bits.
if (opcodeIndex !== 32)
FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 32`);
this.opcodeValue = normalizeNumber(opcodeValue);
}
_assignSpecificAttribute(key, value) {
switch (key) {
case "it": {
const values = String(value).split("|");
for (let i = 0; i < values.length; i++) {
const value = values[i];
switch (value) {
case "in" : this.it.IN = true; break;
case "out" : this.it.OUT = true; break;
case "any" : this.it.IN = true;
this.it.OUT = true; break;
case "last": this.it.LAST = true; break;
case "def" : this.it.DEF = true; break;
default:
this.report(`${this.name}: Unhandled IT value '${value}'`);
}
}
return true;
}
}
return false;
}
_postProcess() {}
operandByName(name) {
const operands = this.operands;
for (let i = 0; i < operands.length; i++) {
const op = operands[i];
if (op.name === name)
return op;
}
return null;
}
}
arm.Instruction = Instruction;
// asmdb.aarch64.ISA
// =================
function mergeGroupData(data, group) {
for (let k in group) {
switch (k) {
case "group":
case "data":
break;
case "ext":
data[k] = (data[k] ? data[k] + " " : "") + group[k];
break;
default:
if (data[k] === undefined)
data[k] = group[k]
break;
}
}
}
class ISA extends base.ISA {
constructor(data) {
super(data);
this.addData(data || NONE);
}
_addInstructions(groups) {
for (let group of groups) {
for (let inst of group.data) {
const sgn = Utils.splitInstructionSignature(inst.inst);
const data = MapUtils.cloneExcept(inst, { "inst": true });
mergeGroupData(data, group)
for (let j = 0; j < sgn.names.length; j++) {
data.name = sgn.names[j];
data.operands = sgn.operands;
if (j > 0)
data.aliasOf = sgn.names[0];
this._addInstruction(new Instruction(this, data));
}
}
}
return this;
}
}
arm.ISA = ISA;
}).apply(this, typeof module === "object" && module && module.exports
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch64"]);

941
db/arm.js Normal file
View File

@@ -0,0 +1,941 @@
// 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
(function($scope, $as) {
"use strict";
function FAIL(msg) { throw new Error("[AArch32] " + msg); }
// Import
// ======
const base = $scope.base ? $scope.base : require("./base.js");
const exp = $scope.exp ? $scope.exp : require("./exp.js")
const hasOwn = Object.prototype.hasOwnProperty;
const dict = base.dict;
const NONE = base.NONE;
const Parsing = base.Parsing;
const MapUtils = base.MapUtils;
// Export
// ======
const arm = $scope[$as] = dict();
// Database
// ========
arm.dbName = "isa_arm.json";
// asmdb.arm.Utils
// ===============
// Can be used to assign the number of bits each part of the opcode occupies.
// NOTE: THUMB instructions that use halfword must always specify the width
// of all registers as many instructictions accept only LO (r0..r7) registers.
const FieldInfo = {
"P" : { "bits": 1 },
"U" : { "bits": 1 },
"W" : { "bits": 1 },
"S" : { "bits": 1 },
"R" : { "bits": 1 },
"H" : { "bits": 1 },
"isFp32": { "bits": 1 },
"F" : { "bits": 1 },
"align" : { "bits": 2 },
"ja" : { "bits": 1 },
"jb" : { "bits": 1 },
"op" : { "bits": 1 }, // TODO: This should be fixed.
"sz" : { "bits": 2 },
"sop" : { "bits": 2 },
"cond" : { "bits": 4 },
"cmode" : { "bits": 4 },
"Cn" : { "bits": 4 },
"Cm" : { "bits": 4 },
"Rd" : { "bits": 4, "read": false, "write": true },
"Rd2" : { "bits": 4, "read": false, "write": true },
"RdLo" : { "bits": 4, "read": false, "write": true },
"RdHi" : { "bits": 4, "read": false, "write": true },
"RdList": { "bits": 4, "read": false, "write": true , "list": true },
"Rx" : { "bits": 4, "read": true , "write": true },
"RxLo" : { "bits": 4, "read": true , "write": true },
"RxHi" : { "bits": 4, "read": true , "write": true },
"Rn" : { "bits": 4, "read": true , "write": false },
"Rm" : { "bits": 4, "read": true , "write": false },
"Ra" : { "bits": 4, "read": true , "write": false },
"Rs" : { "bits": 4, "read": true , "write": false },
"Rs2" : { "bits": 4, "read": true , "write": false },
"RsList": { "bits": 4, "read": true , "write": false , "list": true },
"Sd" : { "bits": 4, "read": false, "write": true },
"Sd2" : { "bits": 4, "read": false, "write": true },
"Sx" : { "bits": 4, "read": true , "write": true },
"Sn" : { "bits": 4, "read": true , "write": false },
"Sm" : { "bits": 4, "read": true , "write": false },
"Ss" : { "bits": 4, "read": true , "write": false },
"Ss2" : { "bits": 4, "read": true , "write": false },
"Dd" : { "bits": 4, "read": false, "write": true },
"Dd2" : { "bits": 4, "read": false, "write": true },
"Dd3" : { "bits": 4, "read": false, "write": true },
"Dd4" : { "bits": 4, "read": false, "write": true },
"Dx" : { "bits": 4, "read": true , "write": true },
"Dx2" : { "bits": 4, "read": true , "write": true },
"Dn" : { "bits": 4, "read": true , "write": false },
"Dn2" : { "bits": 4, "read": true , "write": false },
"Dn3" : { "bits": 4, "read": true , "write": false },
"Dn4" : { "bits": 4, "read": true , "write": false },
"Dm" : { "bits": 4, "read": true , "write": false },
"Ds" : { "bits": 4, "read": true , "write": false },
"Ds2" : { "bits": 4, "read": true , "write": false },
"Ds3" : { "bits": 4, "read": true , "write": false },
"Ds4" : { "bits": 4, "read": true , "write": false },
"Vd" : { "bits": 4, "read": false, "write": true },
"Vd2" : { "bits": 4, "read": false, "write": true },
"Vd3" : { "bits": 4, "read": false, "write": true },
"Vd4" : { "bits": 4, "read": false, "write": true },
"VdList": { "bits": 4, "read": false, "write": true , "list": true },
"Vx" : { "bits": 4, "read": true , "write": true },
"Vx2" : { "bits": 4, "read": true , "write": true },
"Vn" : { "bits": 4, "read": true , "write": false },
"Vm" : { "bits": 4, "read": true , "write": false },
"Vs" : { "bits": 4, "read": true , "write": false },
"Vs2" : { "bits": 4, "read": true , "write": false },
"VsList": { "bits": 4, "read": true , "write": false , "list": true }
};
arm.FieldInfo = FieldInfo;
// ARM utilities.
class Utils {
static splitInstructionSignature(s) {
const names = s.match(/^[\w\|]+/)[0];
s = s.substring(names.length);
const opOffset = s.indexOf(" ")
const suffix = s.substring(0, opOffset).trim();
const operands = opOffset === -1 ? "" : s.substring(opOffset + 1).trim();
return {
names: names.split("|").map((base)=>{ return base + suffix}),
operands: operands
}
}
static parseShiftOp(s) {
const m = s.match(/^(sop|lsl_or_asr|lsl|lsr|asr|ror|rrx) /);
return m ? m[1] : "";
}
static parseDtArray(s) {
const out = [];
if (!s) return out;
const arr = s.split("|");
let i;
// First expand anything between X-Y, for example s8-32 would be expanded to [s8, s16, s32].
for (i = 0; i < arr.length; i++) {
const v = arr[i];
if (v.indexOf("-") !== -1) {
const m = /^([A-Za-z]+)?(\d+)-(\d+)$/.exec(v);
if (!m)
FAIL(`Couldn't parse '${s}' data-type`);
let type = m[1] || "";
let size = parseInt(m[2], 10);
let last = parseInt(m[3], 10);
if (!Utils.checkDtSize(size) || !Utils.checkDtSize(last))
FAIL(`Invalid dt width in '${s}'`);
do {
out.push(type + String(size));
size <<= 1;
} while (size <= last);
}
else {
out.push(v);
}
}
// Now expand 'x' to 's' and 'u'.
i = 0;
while (i < out.length) {
const v = out[i];
if (v.startsWith("x")) {
out.splice(i, 1, "s" + v.substr(1), "u" + v.substr(1));
i += 2;
}
else {
i++;
}
}
return out;
}
static checkDtSize(x) {
return x === 8 || x === 16 || x === 32 || x === 64;
}
}
arm.Utils = Utils;
function normalizeNumber(n) {
return n < 0 ? 0x100000000 + n : n;
}
function decomposeOperand(s) {
const elementSuffix = "[#i]";
let element = null;
let consecutive = 0;
if (s.endsWith(elementSuffix)) {
element = "#i";
s = s.substr(0, s.length - elementSuffix.length);
}
if (s.endsWith("++")) {
consecutive = 2;
s = s.substr(0, s.length - 2);
}
else if (s.endsWith("+")) {
consecutive = 1;
s = s.substr(0, s.length - 1);
}
let m = s.match(/==|\!=|>=|<=|\*/);
let restrict = false;
if (m) {
restrict = s.substr(m.index);
s = s.substr(0, m.index);
}
return {
data : s,
element : element,
restrict: restrict,
consecutive: consecutive
};
}
function splitOpcodeFields(s) {
const arr = s.split("|");
const out = [];
for (let i = 0; i < arr.length; i++) {
const val = arr[i];
if (/^[0-1A-Z]{2,}$/.test(val))
out.push.apply(out, val.match(/([0-1]+)|[A-Z]/g));
else
out.push(val);
}
return out.map((field) => { return field.trim(); });
}
// asmdb.arm.Operand
// =================
// ARM operand.
class Operand extends base.Operand {
constructor(def) {
super(def);
}
hasMemModes() {
return Object.keys(this.memModes).length !== 0;
}
get name() {
switch (this.type) {
case "reg": return this.reg;
case "mem": return this.mem;
case "imm": return this.imm;
case "rel": return this.rel;
default : return "";
}
}
get scale() {
if (this.restrict && this.restrict.startsWith("*"))
return parseInt(this.restrict.substr(1), 10);
else
return 0;
}
}
arm.Operand = Operand;
// asmdb.arm.Instruction
// =====================
function patternFromOperand(key) {
return key;
// return key.replace(/\b(?:[RVDS](?:d|s|n|m|x|x2))\b/, "R");
}
// ARM instruction.
class Instruction extends base.Instruction {
constructor(db, data) {
super(db, data);
// name, operands, encoding, opcode, metadata
const encoding = hasOwn.call(data, "a32") ? "a32" :
hasOwn.call(data, "t32") ? "t32" :
hasOwn.call(data, "t16") ? "t16" : "";
this.name = data.name;
this.it = dict(); // THUMB's 'it' flags.
this.apsr = dict();
this.fpcsr = dict();
this.calc = dict(); // Calculations required to generate opcode.
this.immCond = []; // Immediate value conditions (array of conditions).
this.s = null; // Instruction S flag (null, true, or false).
this.dt = []; // Instruction <dt> field (first data-type).
this.dt2 = []; // Instruction <dt2> field (second data-type).
this.availableFrom = ""; // Instruction supported by from ARMv???.
this.availableUntil = ""; // Instruction supported by until ARMv???.
this._assignOperands(data.operands);
this._assignEncoding(encoding.toUpperCase());
this._assignOpcode(data[encoding]);
for (let k in data) {
if (k === "name" || k == encoding || k === "operands")
continue;
this._assignAttribute(k, data[k]);
}
this._updateOperandsInfo();
this._postProcess();
}
_assignAttribute(key, value) {
switch (key) {
case "it":
for (let it of value.split(" "))
this.it[it.trim()] = true;
break;
case "apsr":
case "fpcsr":
this._assignAttributeKeyValue(key, value);
break;
case "imm":
this.imm = exp.parse(value);
break;
case "calc":
for (let calcKey in value)
this.calc[calcKey] = exp.parse(value[calcKey]);
break;
default:
super._assignAttribute(key, value);
}
}
_assignAttributeKeyValue(name, content) {
const attributes = content.trim().split(/[ ]+/);
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i].trim();
if (!attr)
continue;
const eq = attr.indexOf("=");
let key = eq === -1 ? attr : attr.substr(0, eq);
let val = eq === -1 ? true : attr.substr(eq + 1);
// If the key contains "|" it's a definition of multiple attributes.
if (key.indexOf("|") !== -1) {
const dot = key.indexOf(".");
const base = dot === -1 ? "" : key.substr(0, dot + 1);
const keys = (dot === -1 ? key : key.substr(dot + 1)).split("|");
for (let j = 0; j < keys.length; j++)
this[name][base + keys[j]] = val;
}
else {
this[name][key] = val;
}
}
}
_assignEncoding(s) {
this.arch = s === "T16" || s === "T32" ? "THUMB" : "ARM";
this.encoding = s;
}
_assignOperands(s) {
if (!s) return;
// Split into individual operands and push them to `operands`.
const arr = base.Parsing.splitOperands(s);
for (let i = 0; i < arr.length; i++) {
let def = arr[i];
const op = new Operand(def);
const consecutive = def.match(/(\d+)x\{(.*)\}([+][+]?)/);
if (consecutive)
def = consecutive[2];
op.sign = false;
op.element = null;
op.shiftOp = "";
op.shiftImm = null;
// Handle {optional} attribute.
if (Parsing.isOptional(def)) {
op.optional = true;
def = Parsing.clearOptional(def);
}
// Handle commutativity <-> symbol.
if (Parsing.isCommutative(def)) {
op.commutative = true;
def = Parsing.clearCommutative(def);
}
// Handle shift operation.
let shiftOp = Utils.parseShiftOp(def);
if (shiftOp) {
op.shiftOp = shiftOp;
def = def.substring(shiftOp.length + 1);
}
if (def.startsWith("[")) {
op.type = "mem";
op.memModes = dict();
op.base = null;
op.index = null;
op.offset = null;
let mem = def;
let didHaveMemMode = false;
for (;;) {
if (mem.endsWith("!")) {
op.memModes.preIndex = true;
mem = mem.substring(0, mem.length - 1);
didHaveMemMode = true;
break;
}
if (mem.endsWith("@")) {
op.memModes.postIndex = true;
mem = mem.substring(0, mem.length - 1);
didHaveMemMode = true;
break;
}
if (mem.endsWith("{!}")) {
op.memModes.offset = true;
op.memModes.preIndex = true;
mem = mem.substring(0, mem.length - 3);
didHaveMemMode = true;
continue;
}
if (mem.endsWith("{@}")) {
op.memModes.offset = true;
op.memModes.postIndex = true;
mem = mem.substring(0, mem.length - 3);
didHaveMemMode = true;
continue;
}
break;
}
if (!mem.endsWith("]"))
FAIL(`Unknown memory operand '${mem}' in '${def}'`);
let parts = mem.substring(1, mem.length - 1).split(",").map(function(s) { return s.trim() });
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const m = part.match(/^\{(lsl|sop)\s+#(\w+)\}$/);
if (m) {
op.shiftOp = m[1];
op.shiftImm = m[2];
continue;
}
if (i === 0) {
op.base = dict();
op.base.field = part;
op.base.exp = null;
const m = part.match(/^([A-Za-z]\w*)/);
if (m.length < part.length) {
op.base.exp = exp.parse(part);
op.base.field = m[1];
}
}
else if (part.startsWith("#")) {
let p = part.substring(1);
let u = "1";
let offExp = null;
let offMul = 1;
if (p.startsWith("+/-")) {
u = "U";
p = p.substring(3);
}
const expMatch = p.match(/^([A-Za-z]\w*)==/);
if (expMatch) {
offExp = exp.parse(p);
p = p.substr(0, expMatch[1].length);
}
const mulMatch = p.match(/\s*\*\s*(\d+)$/);
if (mulMatch) {
offMul = parseInt(mulMatch[1]);
p = p.substr(0, mulMatch.index);
}
op.offset = dict();
op.offset.field = p;
op.offset.u = u;
op.offset.exp = offExp;
op.offset.mul = offMul;
}
else {
let p = part;
let u = "1";
if (p.startsWith("+/-")) {
u = "U";
p = p.substring(3);
}
op.index = dict();
op.index.field = p;
op.index.u = u;
const m = p.match(/^([A-Za-z]\w*)/);
if (m.length < p.length) {
op.index.exp = exp.parse(p);
op.index.field = m[1];
}
}
}
if (!op.hasMemModes() && (op.offset || op.index))
op.memModes.offset = true;
op.mem = mem;
}
else if (def.startsWith("#")) {
const obj = decomposeOperand(def);
const imm = obj.data;
op.type = "imm";
op.imm = imm.substring(1); // Immediate operand name.
op.immSize = 0; // Immediate size in bits.
op.restrict = obj.restrict; // Immediate condition.
}
else {
const obj = decomposeOperand(def);
const reg = obj.data;
const type = reg.substr(0, 1).toLowerCase();
const info = FieldInfo[reg];
if (!info)
FAIL(`Unknown register operand '${reg}' in '${def}'`);
op.type = info.list ? "reg-list" : "reg";
op.reg = reg; // Register name (as specified in manual).
op.regType = type; // Register type.
op.regList = !!info.list; // Register list.
op.read = info.read; // Register access (read).
op.write = info.write; // Register access (write).
op.element = obj.element; // Register element[] access.
op.restrict = obj.restrict; // Register condition.
op.consecutive = obj.consecutive;
}
this.operands.push(op);
if (consecutive) {
const count = parseInt(consecutive[1]);
for (let n = 2; n <= count; n++) {
const def = consecutive[3].replace(op.reg, op.reg + n);
const opN = new Operand(def);
opN.type = "reg";
opN.reg = op.reg + n;
opN.regType = op.regType;
opN.read = op.read;
opN.write = op.write;
opN.element = op.element;
opN.consecutive = consecutive[3].length;
this.operands.push(opN);
}
}
}
}
_assignOpcode(s) {
this.opcodeString = s;
let opcodeIndex = 0;
let opcodeValue = 0;
let patternMap = {};
// Split opcode into its fields.
const arr = splitOpcodeFields(s);
const dup = dict();
const fields = this.fields;
const pattern = [];
const fieldMap = Object.create(null);
for (let field of arr) {
fieldMap[field] = true;
}
for (let i = arr.length - 1; i >= 0; i--) {
let key = arr[i];
let m;
if (/^[0-1]+$/.test(key)) {
// This part of the opcode is RAW bits, they contribute to the `opcodeValue`.
opcodeValue |= parseInt(key, 2) << opcodeIndex;
opcodeIndex += key.length;
pattern.unshift("_".repeat(key.length));
}
else {
pattern.unshift(patternFromOperand(key));
patternMap[patternFromOperand(key)] = true;
let size = 0;
let mask = 0;
let bits = 0;
let from = -1;
let lbit = key.startsWith("'");
let hbit = key.endsWith("'");
if ((m = key.match(/\[\s*(\d+)\s*\:\s*(\d+)\s*\]$/))) {
const a = parseInt(m[1], 10);
const b = parseInt(m[2], 10);
if (a < b)
FAIL(`Invalid bit range '${key}' in opcode '${s}'`);
from = b;
size = a - b + 1;
mask = ((1 << size) - 1) << b;
key = key.substr(0, m.index).trim();
}
else if ((m = key.match(/\[\s*(\d+)\s*\]$/))) {
from = parseInt(m[1], 10);
size = 1;
mask = 1 << from;
key = key.substr(0, m.index).trim();
}
else if ((m = key.match(/\:\s*(\d+)$/))) {
size = parseInt(m[1], 10);
bits = size;
key = key.substr(0, m.index).trim();
}
else {
const key_ = key;
if (lbit || hbit) {
from = 0;
if (lbit && hbit)
FAIL(`Couldn't recognize the format of '${key}' in opcode '${s}'`);
if (lbit) {
key = key.substring(1);
}
if (hbit) {
key = key.substring(0, key.length - 1);
from = 4;
}
size = 1;
}
else if (FieldInfo[key]) {
// Sizes of some standard fields can be assigned automatically.
size = FieldInfo[key].bits;
bits = size;
if (fieldMap["'" + key])
from = 1;
}
else if (key.length === 1) {
// Sizes of one-letter fields (like 'U', 'F', etc...) is 1 if not specified.
size = 1;
bits = 1;
}
else {
FAIL(`Couldn't recognize the size of '${key}' in opcode '${s}'`);
}
if (dup[key_] === true) {
bits = 0;
lbit = 0;
hbit = 0;
}
else {
dup[key_] = true;
}
}
let field = fields[key];
if (!field) {
field = {
index: opcodeIndex,
values: [],
bits: 0,
mask: 0,
lbit: 0,
hbit: 0 // Only 1 if a single quote (') was used.
}
fields[key] = field;
}
if (from === -1)
from = field.bits;
field.mask |= mask;
field.bits += bits;
field.lbit += lbit;
field.hbit += hbit;
field.values.push({
index: opcodeIndex,
from: from,
size: size
});
opcodeIndex += size;
}
}
for (let i = 0; i < pattern.length; i++)
if (pattern[i] === 'U')
pattern[i] = "_";
// Normalize all fields.
for (let key in fields) {
const field = fields[key];
// There should be either number of bits or mask, there shouldn't be both.
if (!field.bits && !field.mask)
FAIL(`Part '${key}' of opcode '${s}' contains neither size nor mask`);
if (field.bits && field.mask)
FAIL(`Part '${key}' of opcode '${s}' contains both size and mask`);
if (field.bits)
field.mask = ((1 << field.bits) - 1);
else if (field.mask)
field.bits = 32 - Math.clz32(field.mask);
// Handle field that used single-quote.
if (field.lbit) {
field.mask = (field.mask << 1) | 0x1;
field.bits++;
}
if (field.hbit) {
field.mask |= 1 << field.bits;
field.bits++;
}
const op = this.operandByName(key);
if (op && op.isImm())
op.immSize = field.bits;
}
// Check if the opcode value has the correct number of bits (either 16 or 32).
if (opcodeIndex !== 16 && opcodeIndex !== 32)
FAIL(`The number of bits '${opcodeIndex}' used by the opcode '${s}' doesn't match 16 or 32`);
this.opcodeValue = normalizeNumber(opcodeValue);
}
_assignSpecificAttribute(key, value) {
// Support ARMv?+ and ARMv?- attributes.
if (/^ARM\w+[+-]$/.test(key)) {
const armv = key.substr(0, key.length - 1);
const sign = key.substr(key.length - 1);
if (sign === "+")
this.availableFrom = armv;
else
this.availableUntil = armv;
return true;
}
switch (key) {
case "it": {
const values = String(value).split("|");
for (let i = 0; i < values.length; i++) {
const value = values[i];
switch (value) {
case "in" : this.it.IN = true; break;
case "out" : this.it.OUT = true; break;
case "any" : this.it.IN = true;
this.it.OUT = true; break;
case "last": this.it.LAST = true; break;
case "def" : this.it.DEF = true; break;
default:
this.report(`${this.name}: Unhandled IT value '${value}'`);
}
}
return true;
}
}
return false;
}
// ARM instruction name could consist of name and optional type information
// specified as <dt> and <dt2> in ARM manuals. We parse this information and
// store it to `dt` and `dt2` fields. In addition, we also recognize the `S`
// suffix (uppercase) of the instruction and mark it as `S` instruction. After
// that the name is normalized to be lowercased.
//
// This functionality requires all the instruction data to be already set-up.
_postProcess() {
let s = this.name;
// Parse <dt> and <dt2> fields.
if (s.indexOf(".") !== -1) {
const parts = s.split(".");
this.name = parts[0];
if (parts.length > 3)
FAIL(`Couldn't recognize name attributes of '${s}'`);
for (let i = 1; i < parts.length; i++) {
const dt = Utils.parseDtArray(parts[i]);
if (i === 1)
this.dt = dt;
else
this.dt2 = dt;
}
}
// Recognize "S" suffix.
if (this.name.endsWith("S")) {
this.name = this.name.substr(0, this.name.length - 1) + "s";
this.s = true;
}
this.dt.sort();
}
operandByName(name) {
const operands = this.operands;
for (let i = 0; i < operands.length; i++) {
const op = operands[i];
if (op.name === name)
return op;
}
return null;
}
}
arm.Instruction = Instruction;
// asmdb.arm.ISA
// =============
function mergeGroupData(data, group) {
for (let k in group) {
switch (k) {
case "group":
case "data":
break;
case "ext":
data[k] = (data[k] ? data[k] + " " : "") + group[k];
break;
default:
if (data[k] === undefined)
data[k] = group[k]
break;
}
}
}
class ISA extends base.ISA {
constructor(data) {
super(data);
this.addData(data || NONE);
}
_addInstructions(groups) {
for (let group of groups) {
for (let inst of group.data) {
const sgn = Utils.splitInstructionSignature(inst.inst);
const data = MapUtils.cloneExcept(inst, { "inst": true });
mergeGroupData(data, group)
for (let j = 0; j < sgn.names.length; j++) {
data.name = sgn.names[j];
data.operands = sgn.operands;
if (j > 0)
data.aliasOf = sgn.names[0];
this._addInstruction(new Instruction(this, data));
}
}
}
return this;
}
/*
_addInstructions(instructions) {
for (let i = 0; i < instructions.length; i++) {
const obj = instructions[i];
const sgn = obj.inst;
const sep = sgn.indexOf(" ");
const names = (sep !== -1 ? sgn.substring(0, sep) : sgn).trim().split("/");
const operands = sep !== -1 ? sgn.substring(sep + 1) : "";
const encoding = hasOwn.call(obj, "a32") ? "a32" :
hasOwn.call(obj, "t32") ? "t32" :
hasOwn.call(obj, "t16") ? "t16" : "";
if (!encoding)
FAIL(`Instrution ${names.join("/")} doesn't encoding, it must provide either a32, t32, or t16 field`);
for (let j = 0; j < names.length; j++) {
const inst = new Instruction(this, names[j], operands, encoding.toUpperCase(), obj[encoding], obj);
if (j > 0)
inst.aliasOf = names[0];
this._addInstruction(inst);
}
}
return this;
}
*/
}
arm.ISA = ISA;
}).apply(this, typeof module === "object" && module && module.exports
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "arm"]);

645
db/base.js Normal file
View File

@@ -0,0 +1,645 @@
// 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
(function($scope, $as) {
"use strict";
function FAIL(msg) { throw new Error("[BASE] " + msg); }
// Import.
const hasOwn = Object.prototype.hasOwnProperty;
const exp = $scope.exp ? $scope.exp : require("./exp.js");
// Export.
const base = $scope[$as] = Object.create(null);
base.exp = exp;
function dict(src) {
const dst = Object.create(null);
if (src)
Object.assign(dst, src);
return dst;
}
base.dict = dict;
const NONE = base.NONE = Object.freeze(dict());
// asmdb.base.Symbols
// ==================
const Symbols = Object.freeze({
Commutative: '~'
});
base.Symbols = Symbols;
// asmdb.base.Parsing
// ==================
// Namespace that provides functions related to text parsing.
const Parsing = {
// Get whether the string `s` representing an operand is <implicit>.
isImplicit: function(s) { return s.startsWith("<") && s.endsWith(">"); },
// Clear <implicit> attribute from the given operand string `s`.
clearImplicit: function(s) { return s.substring(1, s.length - 1); },
// Get whether the string `s` representing an operand is {optional}.
isOptional: function(s) { return s.startsWith("{") && s.endsWith("}"); },
// Clear {optional} attribute from the given operand string `s`.
clearOptional: function(s) { return s.substring(1, s.length - 1); },
// Get whether the string `s` representing an operand specifies commutativity.
isCommutative: function(s) { return s.length > 0 && s.charAt(0) === Symbols.Commutative; },
// Clear commutative attribute from the given operand string `s`.
clearCommutative: function(s) { return s.substring(1); },
// Matches a closing bracket in string `s` starting `from` the given index.
// It behaves like `s.indexOf()`, but uses a counter and skips all nested
// matches.
matchClosingChar: function(s, from) {
const len = s.length;
const opening = s.charCodeAt(from);
const closing = opening === 40 ? 31 : // ().
opening === 60 ? 62 : // <>.
opening === 91 ? 93 : // [].
opening === 123 ? 125 : 0; // {}.
let i = from;
let pending = 1;
do {
if (++i >= len)
break;
const c = s.charCodeAt(i);
pending += Number(c === opening);
pending -= Number(c === closing);
} while (pending);
return i;
},
// Split instruction operands into an array containing each operand as a
// trimmed string. This function is similar to `s.split(",")`, however,
// it matches brackets inside the operands and won't just blindly split
// the string based on "," token. If operand contains metadata or it's
// an address it would still be split correctly.
splitOperands: function(s) {
const result = [];
s = s.trim();
if (!s)
return result;
let start = 0;
let i = 0;
let c = "";
for (;;) {
if (i === s.length || (c = s[i]) === ",") {
const op = s.substring(start, i).trim();
if (!op)
FAIL(`Found empty operand in '${s}'`);
result.push(op);
if (i === s.length)
return result;
start = ++i;
continue;
}
if ((c === "<" || c === ">") && i != start) {
i++;
continue;
}
if (c === "[" || c === "{" || c === "(" || c === "<")
i = base.Parsing.matchClosingChar(s, i);
else
i++;
}
}
}
base.Parsing = Parsing;
// asmdb.base.MapUtils
// ===================
const MapUtils = {
cloneExcept(map, except) {
const out = Object.create(null);
for (let k in map) {
if (k in except)
continue
out[k] = map[k];
}
return out;
}
};
base.MapUtils = MapUtils;
// asmdb.base.Operand
// ==================
const OperandFlags = Object.freeze({
Optional : 0x00000001,
Implicit : 0x00000002,
Commutative: 0x00000004,
ZExt : 0x00000008,
ReadAccess : 0x00000010,
WriteAccess: 0x00000020
});
base.OperandFlags = OperandFlags;
class Operand {
constructor(data) {
this.type = ""; // Type of the operand ("reg", "reg-list", "mem", "reg/mem", "imm", "rel").
this.data = data; // The operand's data (possibly processed).
this.flags = 0;
this.reg = ""; // Register operand's definition.
this.mem = ""; // Memory operand's definition.
this.imm = 0; // Immediate operand's size.
this.rel = 0; // Relative displacement operand's size.
this.restrict = ""; // Operand is restricted (specific register or immediate value).
this.read = false; // True if the operand is a read-op from reg/mem.
this.write = false; // True if the operand is a write-op to reg/mem.
this.regType = ""; // Register operand's type.
this.regIndexRel = 0; // Register index is relative to the previous register operand index (0 if not).
this.memSize = -1; // Memory operand's size.
this.immSign = ""; // Immediate sign (any / signed / unsigned).
this.immValue = null; // Immediate value - `null` or `1` (only used by shift/rotate instructions).
this.rwxIndex = -1; // Read/Write (RWX) index.
this.rwxWidth = -1; // Read/Write (RWX) width.
}
_getFlag(flag) {
return (this.flags & flag) != 0;
}
_setFlag(flag, value) {
this.flags = (this.flags & ~flag) | (value ? flag : 0);
return this;
}
get optional() { return this._getFlag(OperandFlags.Optional); }
set optional(value) { this._setFlag(OperandFlags.Optional, value); }
get implicit() { return this._getFlag(OperandFlags.Implicit); }
set implicit(value) { this._setFlag(OperandFlags.Implicit, value); }
get commutative() { return this._getFlag(OperandFlags.Commutative); }
set commutative(value) { this._setFlag(OperandFlags.Commutative, value); }
get zext() { return this._getFlag(OperandFlags.ZExt); }
set zext(value) { this._setFlag(OperandFlags.ZExt, value); }
toString() { return this.data; }
isReg() { return !!this.reg; }
isMem() { return !!this.mem; }
isImm() { return !!this.imm; }
isRel() { return !!this.rel; }
isRegMem() { return this.reg && this.mem; }
isRegOrMem() { return !!this.reg || !!this.mem; }
isRegList() { return this.type === "reg-list" }
isPartialOp() { return false; }
}
base.Operand = Operand;
// asmdb.base.Instruction
// ======================
// Defines interface and properties that each architecture dependent instruction
// must provide even if that particular architecture doesn't use that feature(s).
class Instruction {
constructor(db) {
Object.defineProperty(this, "db", { value: db });
this.name = ""; // Instruction name.
this.arch = "ANY"; // Architecture.
this.encoding = ""; // Encoding type.
this.operands = []; // Instruction operands.
this.implicit = 0; // Indexes of all implicit operands (registers / memory).
this.commutative = 0; // Indexes of all commutative operands.
this.opcodeString = ""; // Instruction opcode as specified in manual.
this.opcodeValue = 0; // Instruction opcode as number (arch dependent).
this.fields = dict(); // Information about each opcode field (arch dependent).
this.operations = dict(); // Operations the instruction performs.
this.io = dict(); // Instruction input / output (CPU flags, states, and other registers).
this.ext = dict(); // ISA extensions required by the instruction.
this.category = dict(); // Instruction categories.
this.specialRegs = dict(); // Information about read/write to special registers.
this.altForm = false; // This is an alternative form, not needed to create a signature.
this.volatile = false; // Instruction is volatile and should not be reordered.
this.control = "none"; // Control flow type (none by default).
this.privilege = ""; // Privilege-level required to execute the instruction.
this.aliasOf = ""; // Instruction is an alias of another instruction
}
get extArray() {
const out = Object.keys(this.ext);
out.sort();
return out;
}
_assignAttribute(key, value) {
switch (key) {
case "ext":
case "io":
case "category":
return this._combineAttribute(key, value);
default:
if (typeof this[key] === undefined)
FAIL(`Cannot assign ${key}=${value}`);
this[key] = value;
break;
}
}
_combineAttribute(key, value) {
if (typeof value === "string")
value = value.split(" ");
if (Array.isArray(value)) {
for (let v of value) {
let pKeys = v;
let pValue = true;
const i = v.indexOf("=");
if (i !== -1) {
pValue = v.substring(i + 1);
pKeys = v.substring(0, i).trim();
}
for (let pk of pKeys.trim().split("|").map(function(s) { return s.trim(); })) {
this[key][pk] = pValue;
}
}
}
else {
for (let k in value)
this[key][k] = value[k];
}
}
_updateOperandsInfo() {
this.implicit = 0;
this.commutative = 0;
for (let i = 0; i < this.operands.length; i++) {
const op = this.operands[i];
if (op.implicit) this.implicit |= (1 << i);
if (op.commutative) this.commutative |= (1 << i);
}
}
isAlias() { return !!this.aliasOf; }
isCommutative() { return this.commutative !== 0; }
hasImplicit() { return this.implicit !== 0; }
hasAttribute(name, matchValue) {
const value = this[name];
if (value === undefined)
return false;
if (matchValue === undefined)
return true;
return value === matchValue;
}
report(msg) {
console.log(`${this}: ${msg}`);
}
toString() {
return `${this.name} ${this.operands.join(", ")}`;
}
}
base.Instruction = Instruction;
// asmdb.base.InstructionGroup
// ===========================
// Instruction group is simply array of function that has some additional
// functionality.
class InstructionGroup extends Array {
constructor() {
super();
if (arguments.length === 1) {
const a = arguments[0];
if (Array.isArray(a)) {
for (let i = 0; i < a.length; i++)
this.push(a[i]);
}
}
}
unionCpuFeatures(name) {
const result = dict();
for (let i = 0; i < this.length; i++) {
const inst = this[i];
const features = inst.ext;
for (let k in features)
result[k] = features[k];
}
return result;
}
checkAttribute(key, value) {
let n = 0;
for (let i = 0; i < this.length; i++)
n += Number(this[i][key] === value);
return n;
}
}
base.InstructionGroup = InstructionGroup;
const EmptyInstructionGroup = Object.freeze(new InstructionGroup());
// asmdb.base.ISA
// ==============
class ISA {
constructor() {
this._instructions = null; // Instruction array (contains all instructions).
this._instructionNames = null; // Instruction names (sorted), regenerated when needed.
this._instructionMap = dict(); // Instruction name to `Instruction[]` mapping.
this._aliases = dict(); // Instruction aliases.
this._cpuLevels = dict(); // Architecture versions.
this._extensions = dict(); // Architecture extensions.
this._attributes = dict(); // Instruction attributes.
this._specialRegs = dict(); // Special registers.
this._shortcuts = dict(); // Shortcuts used by instructions metadata.
this.stats = {
insts : 0, // Number of all instructions.
groups: 0 // Number of grouped instructions (having unique name).
};
}
get instructions() {
let array = this._instructions;
if (array === null) {
array = [];
const map = this.instructionMap;
const names = this.instructionNames;
for (let i = 0; i < names.length; i++)
array.push.apply(array, map[names[i]]);
this._instructions = array;
}
return array;
}
get instructionNames() {
let names = this._instructionNames;
if (names === null) {
names = Object.keys(this._instructionMap);
names.sort();
this._instructionNames = names;
}
return names;
}
get instructionMap() { return this._instructionMap; }
get aliases() { return this._aliases; }
get cpuLevels() { return this._cpuLevels; }
get extensions() { return this._extensions; }
get attributes() { return this._attributes; }
get specialRegs() { return this._specialRegs; }
get shortcuts() { return this._shortcuts; }
query(args, copy) {
if (typeof args !== "object" || !args || Array.isArray(args))
return this._queryByName(args, copy);
const filter = args.filter;
if (filter)
copy = false;
let result = this._queryByName(args.name, copy);
if (filter)
result = result.filter(filter, args.filterThis);
return result;
}
_queryByName(name, copy) {
let result = EmptyInstructionGroup;
const map = this._instructionMap;
if (typeof name === "string") {
const insts = map[name];
if (insts) result = insts;
return copy ? result.slice() : result;
}
if (Array.isArray(name)) {
const names = name;
for (let i = 0; i < names.length; i++) {
const insts = map[names[i]];
if (!insts) continue;
if (result === EmptyInstructionGroup)
result = new InstructionGroup();
for (let j = 0; j < insts.length; j++)
result.push(insts[j]);
}
return result;
}
result = this.instructions;
return copy ? result.slice() : result;
}
forEachGroup(cb, thisArg) {
const map = this._instructionMap;
const names = this.instructionNames;
for (let i = 0; i < names.length; i++) {
const name = names[i];
cb.call(thisArg, name, map[name]);
}
return this;
}
addData(data) {
if (typeof data !== "object" || !data)
FAIL("ISA.addData(): data argument must be object");
if (data.cpuLevels) this._addCpuLevels(data.cpuLevels);
if (data.specialRegs) this._addSpecialRegs(data.specialRegs);
if (data.shortcuts) this._addShortcuts(data.shortcuts);
if (data.instructions) this._addInstructions(data.instructions);
if (data.postproc) this._postProc(data.postproc);
}
_postProc(groups) {
for (let group of groups) {
for (let iRule of group.instructions) {
const names = iRule.inst.split(" ");
for (let name of names) {
const insts = this._instructionMap[name];
if (!insts)
FAIL(`Instruction ${name} referenced by '${group.group}' group doesn't exist`);
for (let k in iRule) {
if (k === "inst" || k === "data")
continue;
for (let inst of insts) {
inst._assignAttribute(k, iRule[k]);
}
}
}
}
}
}
_addCpuLevels(items) {
if (!Array.isArray(items))
FAIL("Property 'cpuLevels' must be array");
for (let i = 0; i < items.length; i++) {
const item = items[i];
const name = item.name;
const obj = {
name: name
};
this._cpuLevels[name] = obj;
}
}
_addExtensions(items) {
if (!Array.isArray(items))
FAIL("Property 'extensions' must be array");
for (let i = 0; i < items.length; i++) {
const item = items[i];
const name = item.name;
const obj = {
name: name,
from: item.from || ""
};
this._extensions[name] = obj;
}
}
_addAttributes(items) {
if (!Array.isArray(items))
FAIL("Property 'attributes' must be array");
for (let i = 0; i < items.length; i++) {
const item = items[i];
const name = item.name;
const type = item.type;
if (!/^(?:flag|string|string\[\])$/.test(type))
FAIL(`Unknown attribute type '${type}'`);
const obj = {
name: name,
type: type,
doc : item.doc || ""
};
this._attributes[name] = obj;
}
}
_addSpecialRegs(items) {
if (!Array.isArray(items))
FAIL("Property 'specialRegs' must be array");
for (let i = 0; i < items.length; i++) {
const item = items[i];
const name = item.name;
const obj = {
name : name,
group: item.group || name,
doc : item.doc || ""
};
this._specialRegs[name] = obj;
}
}
_addShortcuts(items) {
if (!Array.isArray(items))
FAIL("Property 'shortcuts' must be array");
for (let i = 0; i < items.length; i++) {
const item = items[i];
const name = item.name;
const expand = item.expand;
if (!name || !expand)
FAIL("Shortcut must contain 'name' and 'expand' properties");
const obj = {
name : name,
expand: expand,
doc : item.doc || ""
};
this._shortcuts[name] = obj;
}
}
_addInstructions(instructions) {
FAIL("ISA._addInstructions() must be reimplemented");
}
_addInstruction(inst) {
let group;
if (hasOwn.call(this._instructionMap, inst.name)) {
group = this._instructionMap[inst.name];
}
else {
group = new InstructionGroup();
this._instructionNames = null;
this._instructionMap[inst.name] = group;
this.stats.groups++;
}
if (inst.aliasOf)
this._aliases[inst.name] = inst.aliasOf;
group.push(inst);
this.stats.insts++;
this._instructions = null;
return this;
}
}
base.ISA = ISA;
}).apply(this, typeof module === "object" && module && module.exports
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "base"]);

635
db/exp.js Normal file
View File

@@ -0,0 +1,635 @@
// 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
(function($scope, $as) {
"use strict";
const hasOwn = Object.prototype.hasOwnProperty;
// Supported Operators
// -------------------
const kUnaryOperators = {
"-": {prec: 3, rtl : 1, emit: "-@1" },
"~": {prec: 3, rtl : 1, emit: "~@1" },
"!": {prec: 3, rtl : 1, emit: "!@1" }
};
const kBinaryOperators = {
"*" : { prec: 5, rtl : 0, emit: "@1 * @2" },
"/" : { prec: 5, rtl : 0, emit: "@1 / @2" },
"%" : { prec: 5, rtl : 0, emit: "@1 % @2" },
"+" : { prec: 6, rtl : 0, emit: "@1 + @2" },
"-" : { prec: 6, rtl : 0, emit: "@1 - @2" },
">>": { prec: 7, rtl : 0, emit: "@1 >> @2" },
"<<": { prec: 7, rtl : 0, emit: "@1 << @2" },
"<" : { prec: 9, rtl : 0, emit: "@1 < @2" },
">" : { prec: 9, rtl : 0, emit: "@1 > @2" },
"<=": { prec: 9, rtl : 0, emit: "@1 <= @2" },
">=": { prec: 9, rtl : 0, emit: "@1 >= @2" },
"==": { prec:10, rtl : 0, emit: "@1 == @2" },
"!=": { prec:10, rtl : 0, emit: "@1 != @2" },
"&" : { prec:11, rtl : 0, emit: "@1 & @2" },
"^" : { prec:12, rtl : 0, emit: "@1 ^ @2" },
"|" : { prec:13, rtl : 0, emit: "@1 | @2" },
"&&": { prec:14, rtl : 0, emit: "@1 && @2" },
"||": { prec:15, rtl : 0, emit: "@1 || @2" },
"?" : { prec:16, rtl : 0, emit: "@1 ? @2" },
":" : { prec:16, rtl : 0, emit: "@1 : @2" }
};
const kMaxOperatorLen = 4;
function rightAssociate(info, bPrec) {
return info.prec > bPrec || (info.prec === bPrec && info.rtl);
}
// Expression Error
// ----------------
// Contains `message` and `position` members. If the `position` is not `-1` then it is
// a zero-based index, which points to a first character of the token near the error.
class ExpressionError extends Error {
constructor(message, position) {
super(message);
this.name = "ExpressionError";
this.message = message;
this.position = position != null ? position : -1;
}
}
function throwTokenizerError(token) {
throw new ExpressionError(`Unexpected token '${token.data}'`, token.position);
}
function throwExpressionError(message, position) {
throw new ExpressionError(message, position);
}
// Expression Tree
// ---------------
function mustEnclose(node) {
return node.isUnary() ? node.child.isOperator() : node.isBinary() ? true : false;
}
class ExpNode {
constructor(type) { this.type = type; }
isImm() { return this.type === "imm"; }
isVar() { return this.type === "var"; }
isCall() { return this.type === "call"; }
isUnary() { return this.type === "unary"; }
isBinary() { return this.type === "binary"; }
isOperator() { return this.type === "unary" || this.type === "binary"; }
info() { return null; }
clone() { throw new Error("ExpNode.clone() must be overridden"); }
toString(ctx) { throw new Error("ExpNode.toString() must be overridden"); }
}
class ImmNode extends ExpNode {
constructor(imm) {
super("imm");
this.imm = imm || 0;
}
clone() { return new ImmNode(this.imm); }
toString(ctx) { return ctx ? ctx.stringifyImmediate(this.imm) : String(this.imm); }
}
class VarNode extends ExpNode {
constructor(name) {
super("var");
this.name = name || "";
}
clone() { return new VarNode(this.var); }
toString(ctx) { return ctx ? ctx.stringifyVariable(this.name) : String(this.name); }
}
class CallNode extends ExpNode {
constructor(name, args) {
super("call");
this.name = name || "";
this.args = args || [];
}
clone() { return new CallNode(this.name, this.args.map(function(arg) { return arg.clone(); })); }
toString(ctx) {
if (this.name === "$bit") {
return `((${this.args[0]} >> ${this.args[1]}) & 1)`;
}
else {
let argsCode = this.args.map(function(arg) { return arg.toString(ctx); }).join(", ");
if (ctx)
return `${ctx.stringifyFunction(this.name)}(${argsCode})`;
else
return `${this.name}(${argsCode})`;
}
}
}
class UnaryNode extends ExpNode {
constructor(op, child) {
if (!hasOwn.call(kUnaryOperators, op))
throw new Error(`Invalid unary operator '${op}`);
super("unary");
this.op = op;
this.child = child || null;
}
info() { return kUnaryOperators[this.op]; }
clone() { return new UnaryNode(this.op, this.left ? this.left.clone() : null); }
toString(ctx) {
return this.info().emit.replace(/@1/g, () => {
const node = this.child;
const code = node.toString(ctx);
return mustEnclose(node) ? `(${code})` : code;
});
}
}
class BinaryNode extends ExpNode {
constructor(op, left, right) {
if (!hasOwn.call(kBinaryOperators, op))
throw new Error(`Invalid binary operator '${op}`);
super("binary");
this.op = op || "";
this.left = left || null;
this.right = right || null;
}
info() { return kBinaryOperators[this.op]; }
clone() { return new BinaryNode(this.op, this.left ? this.left.clone() : null, this.right ? this.right.clone() : null); }
toString(ctx) {
return this.info().emit.replace(/@[1-2]/g, (p) => {
const node = p === "@1" ? this.left : this.right;
const code = node.toString(ctx);
return mustEnclose(node) ? `(${code})` : code;
});
}
}
function Imm(imm) { return new ImmNode(imm); }
function Var(name) { return new VarNode(name); }
function Call(name, args) { return new CallNode(name, args); }
function Unary(op, child) { return new UnaryNode(op, child); }
function Binary(op, left, right) { return new BinaryNode(op, left, right); }
/*
// TODO: Unused, remove?
function Negate(child) { return Unary("-", child); }
function BitNot(child) { return Unary("~", child); }
function Add(left, right) { return Binary("+", left, right); }
function Sub(left, right) { return Binary("-", left, right); }
function Mul(left, right) { return Binary("*", left, right); }
function Div(left, right) { return Binary("/", left, right); }
function Mod(left, right) { return Binary("%", left, right); }
function Shl(left, right) { return Binary("<<", left, right); }
function Shr(left, right) { return Binary(">>", left, right); }
function BitAnd(left, right) { return Binary("&", left, right); }
function BitOr(left, right) { return Binary("|", left, right); }
function BitXor(left, right) { return Binary("^", left, right); }
function Eq(left, right) { return Binary("==", left, right); }
function Ne(left, right) { return Binary("!=", left, right); }
function Lt(left, right) { return Binary("<", left, right); }
function Le(left, right) { return Binary("<=", left, right); }
function Gt(left, right) { return Binary(">", left, right); }
function Ge(left, right) { return Binary(">=", left, right); }
function And(left, right) { return Binary("&&", left, right); }
function Or(left, right) { return Binary("||", left, right); }
*/
// Expression Tokenizer
// --------------------
const kCharNone = 0; // '_' - Character category - Invalid or <end>.
const kCharSpace = 1; // 'S' - Character category - Space.
const kCharAlpha = 2; // 'A' - Character category - Alpha [A-Za-z_].
const kCharDigit = 3; // 'D' - Character category - Digit [0-9].
const kCharPunct = 4; // '$' - Character category - Punctuation.
const Category = (function(_, S, A, D, $) {
const Table = [
_,_,_,_,_,_,_,_,_,S,S,S,S,S,_,_, // 000-015 |......... ..|
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, // 016-031 |................|
S,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$, // 032-047 | !"#$%&'()*+,-./|
D,D,D,D,D,D,D,D,D,D,$,$,$,$,$,$, // 048-063 |0123456789:;<=>?|
$,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, // 064-079 |@ABCDEFGHIJKLMNO|
A,A,A,A,A,A,A,A,A,A,A,$,$,$,$,A, // 080-095 |PQRSTUVWXYZ[\]^_|
$,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A, // 096-111 |`abcdefghijklmno|
A,A,A,A,A,A,A,A,A,A,A,$,$,$,$,_, // 112-127 |pqrstuvwxyz{|}~ |
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, // 128-143 |................|
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ // 144-159 |................|
];
const kTableLength = Table.length;
return function(c) {
if (c < kTableLength)
return Table[c];
return kCharNone;
};
})(kCharNone, kCharSpace, kCharAlpha, kCharDigit, kCharPunct);
const kTokenNone = 0;
const kTokenPunct = 1;
const kTokenIdent = 2;
const kTokenValue = 3;
function newToken(type, position, data, value) {
return {
type : type, // Token type, see `kToken...`.
position: position, // Token position in expression's source.
data : data, // Token data (content) as string.
value : value // Token value (only if the token is a value).
};
}
const NoToken = newToken(kTokenNone, -1, "<end>", null);
// Must be reset before it can be used, use `RegExp.lastIndex`.
const reValue = /(?:(?:\d*\.\d+|\d+)(?:[E|e][+|-]?\d+)?)/g;
function tokenize(source) {
const len = source.length;
const tokens = [];
let i = 0, j = 0; // Current index in `source` and temporary.
let start = 0; // Current token start position.
let data = ""; // Current token data (content) as string.
let c, cat; // Current character code and category.
while (i < len) {
cat = Category(c = source.charCodeAt(i));
if (cat === kCharSpace) {
i++;
}
else if (cat === kCharDigit) {
const n = tokens.length - 1;
if (n >= 0 && tokens[n].data === "." && source[i - 1] === ".") {
tokens.length = n;
i--;
}
reValue.lastIndex = i;
data = reValue.exec(source)[0];
tokens.push(newToken(kTokenValue, i, data, parseFloat(data)));
i += data.length;
}
else if (cat === kCharAlpha) {
start = i;
while (++i < len && ((cat = Category(source.charCodeAt(i))) === kCharAlpha || cat === kCharDigit))
continue;
data = source.substring(start, i);
tokens.push(newToken(kTokenIdent, start, data, null));
}
else if (cat === kCharPunct) {
start = i;
while (++i < len && Category(source.charCodeAt(i)) === kCharPunct)
continue;
data = source.substring(start, i);
do {
for (j = Math.min(i - start, kMaxOperatorLen); j > 0; j--) {
const part = source.substr(start, j);
if (hasOwn.call(kUnaryOperators, part) || hasOwn.call(kBinaryOperators, part) || j === 1) {
tokens.push(newToken(kTokenPunct, start, part, null));
start += j;
break;
}
}
} while (start < i);
}
else {
throwExpressionError(`Unrecognized character '0x${c.toString(16)}'`, i);
}
}
return tokens;
}
// Expression Parser
// -----------------
class Parser {
constructor(tokens) {
this.tokens = tokens;
this.tIndex = 0;
}
peek() { return this.tIndex < this.tokens.length ? this.tokens[this.tIndex ] : NoToken; }
next() { return this.tIndex < this.tokens.length ? this.tokens[this.tIndex++] : NoToken; }
skip() { this.tIndex++; return this; }
back(token) { this.tIndex -= +(token !== NoToken); return this; }
parse() {
// The root expression cannot be empty.
let token = this.peek();
if (token === NoToken)
throwExpressionError("Expression cannot be empty", 0);
const exp = this.parseExpression();
// The root expression must reach the end of the input.
token = this.peek();
if (token !== NoToken)
throwTokenizerError(token);
return exp;
}
parseExpression() {
const stack = [];
let value = null;
let token = null;
for (;;) {
// The only case of value not being `null` is after ternary-if. In that
// case the value was already parsed so we want to skip this section.
if (value === null) {
let unaryFirst = null;
let unaryLast = null;
token = this.next();
// Parse a possible unary operator(s).
if (token.type === kTokenPunct) {
do {
const opName = token.data;
const opInfo = kUnaryOperators[opName];
if (!opInfo)
break;
const node = Unary(opName);
if (unaryLast)
unaryLast.child = node;
else
unaryFirst = node;
unaryLast = node;
token = this.next();
} while (token.type === kTokenPunct);
}
// Parse a value, variable, function call, or nested expression.
if (token.type === kTokenValue) {
value = Imm(token.value);
}
else if (token.type === kTokenIdent) {
const name = token.data;
const after = this.peek();
if (after.data === "(")
value = this.parseCall(token.data);
else if (after.data === "[")
value = this.parseBitAccess(token.data);
else
value = Var(name);
}
else if (token.data === "(") {
value = this.parseExpression();
token = this.next();
if (token.data !== ")")
throwTokenizerError(token);
}
else {
throwTokenizerError(token);
}
// Replace the value with the top-level unary operator, if parsed.
if (unaryFirst) {
unaryLast.child = value;
value = unaryFirst;
}
}
// Parse a possible binary operator - the loop must repeat, if present.
token = this.peek();
if (token.type === kTokenPunct && hasOwn.call(kBinaryOperators, token.data)) {
const opName = token.data;
if (opName === ":")
break;
// Consume the token.
this.skip();
const bNode = Binary(opName, null, null);
if (!stack.length) {
bNode.left = value;
stack.push(bNode);
}
else {
let aNode = stack.pop();
let aPrec = aNode.info().prec;
let bPrec = bNode.info().prec;
if (aPrec > bPrec) {
aNode.right = bNode;
bNode.left = value;
stack.push(aNode, bNode);
}
else {
aNode.right = value;
// Advance to the top-most op that has less/equal precedence than `bPrec`.
while (stack.length) {
if (rightAssociate(aNode.info(), bPrec))
break;
aNode = stack.pop();
}
if (!stack.length && !rightAssociate(aNode.info(), bPrec)) {
bNode.left = aNode;
stack.push(bNode);
}
else {
const tmp = aNode.right;
aNode.right = bNode;
bNode.left = tmp;
stack.push(aNode, bNode);
}
}
}
// Parse "<cond> {ternary-if} <taken> {ternary-else} <not-taken>".
if (opName === "?") {
const ternLeft = this.parseExpression();
const ternTok = this.next();
if (ternTok.data !== ":")
throwExpressionError(`Unterminated ternary if '${token.data}'`, token.position);
const ternRight = this.parseExpression();
value = Binary(opName, info, ternLeft, ternRight);
}
else {
value = null;
}
continue;
}
break;
}
if (value === null)
throwExpressionError("Invalid expression");
if (stack.length !== 0) {
stack[stack.length - 1].right = value;
value = stack[0];
}
return value;
}
parseCall(name) {
const args = [];
let token = this.next();
if (token.data !== "(")
throwTokenizerError(token);
for (;;) {
token = this.peek();
if (token.data === ")")
break;
if (args.length !== 0) {
if (token.data !== ",")
throwTokenizerError(token);
this.skip();
}
args.push(this.parseExpression());
}
this.skip();
return Call(name, args);
}
parseBitAccess(name) {
let token = this.next();
if (token.data !== "[")
throwTokenizerError(token);
token = this.next();
if (token.type != kTokenValue)
throwTokenizerError(token);
const index = token.value;
token = this.next();
if (token.data !== "]")
throwTokenizerError(token);
return Call("$bit", [Var(name), index]);
}
}
function parse(source) {
const tokens = tokenize(source);
return new Parser(tokens).parse();
}
// Expression Visitors
// -------------------
class Visitor {
visit(node) {
switch (node.type) {
case "imm":
case "var": {
break;
}
case "call": {
for (let arg of node.args)
this.visit(arg);
break;
}
case "unary": {
if (node.child)
this.visit(node.child);
break;
}
case "binary": {
if (node.left)
this.visit(node.left);
if (node.right)
this.visit(node.right);
break;
}
default: {
throw new Error(`Visitor.visit(): Unknown node type '${node.type}'`);
}
}
}
}
class Collector extends Visitor {
constructor(nodeType, dst) {
super();
this.dict = dst || Object.create(null);
this.nodeType = nodeType;
}
visit(node) {
if (node.type === this.nodeType) {
if (hasOwn.call(this.dict, node.name))
this.dict[node.name]++;
else
this.dict[node.name] = 1;
}
super.visit(node);
}
}
function collectVars(node, dst) {
const collector = new Collector("var", dst);
collector.visit(node)
return collector.dict;
}
function collectCalls(node, dst) {
const collector = new Collector("call", dst);
collector.visit(node)
return collector.dict;
}
// Exports
// -------
$scope[$as] = {
Imm: Imm,
Var: Var,
Call: Call,
Unary: Unary,
Binary: Binary,
Visitor: Visitor,
ExpressionError: ExpressionError,
parse: parse,
collectVars: collectVars,
collectCalls: collectCalls
};
}).apply(this, typeof module === "object" && module && module.exports
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "exp"]);

11
db/index.js Normal file
View File

@@ -0,0 +1,11 @@
// 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
"use strict";
exports.base = require("./base.js");
exports.arm = require("./arm.js");
exports.aarch64 = require("./aarch64.js");
exports.x86 = require("./x86.js");

3743
db/isa_aarch64.json Normal file

File diff suppressed because it is too large Load Diff

15
db/isa_aarch64_sme.json Normal file
View File

@@ -0,0 +1,15 @@
{
"instructions": [
{"category": "SME", "ext": "SME", "data": [
{"inst": "smstart {#sme_mode=1}" , "op": "11010101|00|000011|0100|0|op:2|1|011|11111" , "imm": "ImmSMEMode(sme_mode)"},
{"inst": "smstop {#sme_mode=1}" , "op": "11010101|00|000011|0100|0|op:2|0|011|11111" , "imm": "ImmSMEMode(sme_mode)"},
{"inst": "eorbt Zd.t, Zn.t, Zm.t" , "op": "01000101|sz|0|Zm|100100|Zn|Zda"},
{"inst": "eortb Zd.t, Zn.t, Zm.t" , "op": "01000101|sz|0|Zm|100101|Zn|Zda"},
{"inst": "TODO_psel Pd, Pn, Pm.t[Wv, #imm]" , "op": "00100101|sz|0110011100010|Pg|0|Pdn"},
{"inst": "revd Zd.Q, Pg/M, Zn.Q" , "op": "00000101|00|101110100|Pg:3|Zn|Zd"},
{"inst": "sclamp Zd.t, Zn.t, Zm.t" , "op": "01000100|sz|0|Zm|110000|Zn|Zda"},
{"inst": "uclamp Zd.t, Zn.t, Zm.t" , "op": "01000100|sz|0|Zm|110001|Zn|Zda"}
]}
]
}

2454
db/isa_arm.json Normal file

File diff suppressed because it is too large Load Diff

4600
db/isa_x86.json Normal file

File diff suppressed because it is too large Load Diff

29
db/package.json Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "asmdb",
"version": "0.1.0",
"license": "Unlicense",
"engines": { "node": ">=8" },
"description": "Instructions database and utilities for X86/X64 and ARM (THUMB/A32/A64) architectures.",
"keywords": [
"asm", "assembler", "database", "instructions",
"arm", "thumb", "thumb2", "a32", "a64", "aarch32", "aarch64",
"x86", "x86_64", "x64", "amd64"
],
"homepage": "https://github.com/asmjit/asmjit/db",
"bugs": {
"url": "https://github.com/asmjit/asmjit/issues"
},
"contributors": [
"Petr Kobalicek <kobalicek.petr@gmail.com> (kobalicek.com)"
],
"main": "index.js",
"repository" : {
"type": "git",
"url": "https://github.com/asmjit/asmjit.git"
}
}

1005
db/x86.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -18,9 +18,8 @@
//! ### Supported Instructions
//!
//! - Emitters:
//! - \ref a64::EmitterExplicitT - Provides all instructions that use explicit
//! operands, provides also utility functions. The member functions provided
//! are part of all ARM/AArch64 emitters.
//! - \ref a64::EmitterExplicitT - Provides all instructions that use explicit operands, provides also utility
//! functions. The member functions provided are part of all AArch64 emitters.
//!
//! - Instruction representation:
//! - \ref a64::Inst::Id - instruction identifiers.
@@ -32,8 +31,8 @@
//! - \ref arm::GpW - 32-bit register.
//! - \ref arm::GpX - 64-bit register.
//! - \ref arm::Vec - Vector (SIMD) register:
//! - \ref arm::VecB - 8-bit SIMD register (AArch64 only).
//! - \ref arm::VecH - 16-bit SIMD register (AArch64 only).
//! - \ref arm::VecB - 8-bit SIMD register.
//! - \ref arm::VecH - 16-bit SIMD register.
//! - \ref arm::VecS - 32-bit SIMD register.
//! - \ref arm::VecD - 64-bit SIMD register.
//! - \ref arm::VecV - 128-bit SIMD register.
@@ -46,7 +45,7 @@
//! ### Other
//!
//! - \ref arm::Shift - Shift operation and value.
//! - \ref a64::Utils - Utilities that can help during code generation for AArch64.
//! - \ref arm::Utils - Utilities that can help during code generation for AArch32 and AArch64.
#include "./arm.h"
#include "./arm/a64assembler.h"
@@ -56,7 +55,6 @@
#include "./arm/a64globals.h"
#include "./arm/a64instdb.h"
#include "./arm/a64operand.h"
#include "./arm/a64utils.h"
#endif // ASMJIT_A64_H_INCLUDED

View File

@@ -11,19 +11,32 @@
//! ### Namespaces
//!
//! - \ref arm - arm namespace provides common functionality for both AArch32 and AArch64 backends.
//! - \ref a32 - a32 namespace provides support for AArch32 architecture. In addition it includes
//! \ref arm namespace, so you can only use a single namespace when targeting AArch32 architecture.
//! - \ref a64 - a64 namespace provides support for AArch64 architecture. In addition it includes
//! \ref arm namespace, so you can only use a single namespace when targeting AArch64 architecture.
//!
//! ### Emitters
//!
//! - AArch64
//! - \ref a32::Assembler - AArch32 assembler (must read, provides examples).
//! - \ref a64::Assembler - AArch64 assembler (must read, provides examples).
//! - \ref a32::Builder - AArch32 builder.
//! - \ref a64::Builder - AArch64 builder.
//! - \ref a32::Compiler - AArch32 compiler.
//! - \ref a64::Compiler - AArch64 compiler.
//! - \ref a32::Emitter - AArch32 emitter (abstract).
//! - \ref a64::Emitter - AArch64 emitter (abstract).
//!
//! ### Supported Instructions
//!
//! - AArch32:
//! - Emitters:
//! - \ref a32::EmitterExplicitT - Provides all instructions that use explicit operands, provides also
//! utility functions. The member functions provided are part of all AArch32 emitters.
//! - Instruction representation:
//! - \ref a32::Inst::Id - instruction identifiers.
//!
//! - AArch64:
//! - Emitters:
//! - \ref a64::EmitterExplicitT - Provides all instructions that use explicit operands, provides also
@@ -36,7 +49,7 @@
//! - \ref arm::Reg - Base class for any AArch32/AArch64 register.
//! - \ref arm::Gp - General purpose register:
//! - \ref arm::GpW - 32-bit register.
//! - \ref arm::GpX - 64-bit register.
//! - \ref arm::GpX - 64-bit register (AArch64 only).
//! - \ref arm::Vec - Vector (SIMD) register:
//! - \ref arm::VecB - 8-bit SIMD register (AArch64 only).
//! - \ref arm::VecH - 16-bit SIMD register (AArch64 only).
@@ -53,10 +66,11 @@
//!
//! - \ref arm::Shift - Shift operation and value (both AArch32 and AArch64).
//! - \ref arm::DataType - Data type that is part of an instruction in AArch32 mode.
//! - \ref a64::Utils - Utilities that can help during code generation for AArch64.
//! - \ref arm::Utils - Utilities that can help during code generation for AArch32 and AArch64.
#include "./core.h"
#include "./arm/armglobals.h"
#include "./arm/armoperand.h"
#include "./arm/armutils.h"
#endif // ASMJIT_ARM_H_INCLUDED

View File

@@ -9,6 +9,7 @@
#include "../core/archtraits.h"
#include "../core/misc_p.h"
#include "../core/type.h"
#include "../arm/a64globals.h"
#include "../arm/a64operand.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
@@ -24,7 +25,7 @@ static const constexpr ArchTraits a64ArchTraits = {
// Reserved.
{ 0, 0, 0 },
// HW stack alignment (AArch64 requires stack aligned to 64 bytes).
// HW stack alignment (AArch64 requires stack aligned to 16 bytes at HW level).
16,
// Min/max stack offset - byte addressing is the worst, VecQ addressing the best.
@@ -39,12 +40,12 @@ static const constexpr ArchTraits a64ArchTraits = {
}},
// RegInfo.
#define V(index) OperandSignature{arm::RegTraits<RegType(index)>::kSignature}
#define V(index) OperandSignature{RegTraits<RegType(index)>::kSignature}
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
#undef V
// RegTypeToTypeId.
#define V(index) TypeId(arm::RegTraits<RegType(index)>::kTypeId)
#define V(index) TypeId(RegTraits<RegType(index)>::kTypeId)
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
#undef V

View File

@@ -14,10 +14,10 @@
#include "../core/misc_p.h"
#include "../core/support.h"
#include "../arm/armformatter_p.h"
#include "../arm/armutils.h"
#include "../arm/a64assembler.h"
#include "../arm/a64emithelper_p.h"
#include "../arm/a64instdb_p.h"
#include "../arm/a64utils.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
@@ -398,14 +398,6 @@ static inline bool encodeLMH(uint32_t sizeField, uint32_t elementIndex, LMHImm*
return elementIndex <= maxElementIndex;
}
// [.......A|B.......|.......C|D.......|.......E|F.......|.......G|H.......]
static inline uint32_t encodeImm64ByteMaskToImm8(uint64_t imm) noexcept {
return uint32_t(((imm >> (7 - 0)) & 0b00000011) | // [.......G|H.......]
((imm >> (23 - 2)) & 0b00001100) | // [.......E|F.......]
((imm >> (39 - 4)) & 0b00110000) | // [.......C|D.......]
((imm >> (55 - 6)) & 0b11000000)); // [.......A|B.......]
}
// a64::Assembler - Opcode
// =======================
@@ -3753,7 +3745,7 @@ Case_BaseLdurStur:
goto InvalidImmediate;
}
else if (imm) {
shift = Support::ctz(imm) & 0x7u;
shift = Support::ctz(imm) & ~0x7u;
imm >>= shift;
if (imm > 0xFFu || shift > maxShift)
@@ -4056,7 +4048,7 @@ Case_BaseLdurStur:
goto InvalidImmediate;
if (Utils::isByteMaskImm8(imm64)) {
imm8 = encodeImm64ByteMaskToImm8(imm64);
imm8 = Utils::encodeImm64ByteMaskToImm8(imm64);
}
else {
// Change from D to S and from 64-bit imm to 32-bit imm if this

View File

@@ -3,8 +3,8 @@
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_ARMEMITHELPER_P_H_INCLUDED
#define ASMJIT_ARM_ARMEMITHELPER_P_H_INCLUDED
#ifndef ASMJIT_ARM_A64EMITHELPER_P_H_INCLUDED
#define ASMJIT_ARM_A64EMITHELPER_P_H_INCLUDED
#include "../core/api-config.h"
@@ -47,4 +47,4 @@ void assignEmitterFuncs(BaseEmitter* emitter);
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_ARMEMITHELPER_P_H_INCLUDED
#endif // ASMJIT_ARM_A64EMITHELPER_P_H_INCLUDED

View File

@@ -84,17 +84,6 @@ struct EmitterExplicitT {
//! \endcond
// --------------------------------------------------------------------------
// [Options]
// --------------------------------------------------------------------------
protected:
inline This& _addInstOptions(InstOptions options) noexcept {
static_cast<This*>(this)->addInstOptions(options);
return *static_cast<This*>(this);
}
public:
//! \name General Purpose Instructions
//! \{
@@ -1119,14 +1108,14 @@ public:
//! \}
//! \name FJCVTZS Instruction (ARMv8.3-A)
//! \name JSCVT Instruction (ARMv8.3-A)
//! \{
ASMJIT_INST_2x(fjcvtzs, Fjcvtzs_v, Gp, Vec);
//! \}
//! \name FP16FML Instructions (ARMv8.4-A, optional in ARMv8.2-A)
//! \name FHM Instructions
//! \{
ASMJIT_INST_3x(fmlal, Fmlal_v, Vec, Vec, Vec);

View File

@@ -19,243 +19,6 @@
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
// a64::FormatterInternal - Format Register
// ========================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
RegType regType,
uint32_t rId,
uint32_t elementType,
uint32_t elementIndex) noexcept {
DebugUtils::unused(flags);
DebugUtils::unused(arch);
static const char bhsdq[] = "bhsdq";
bool virtRegFormatted = false;
#ifndef ASMJIT_NO_COMPILER
if (Operand::isVirtId(rId)) {
if (emitter && emitter->isCompiler()) {
const BaseCompiler* cc = static_cast<const BaseCompiler*>(emitter);
if (cc->isVirtIdValid(rId)) {
VirtReg* vReg = cc->virtRegById(rId);
ASMJIT_ASSERT(vReg != nullptr);
const char* name = vReg->name();
if (name && name[0] != '\0')
ASMJIT_PROPAGATE(sb.append(name));
else
ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId))));
virtRegFormatted = true;
}
}
}
#else
DebugUtils::unused(emitter, flags);
#endif
if (!virtRegFormatted) {
char letter = '\0';
switch (regType) {
case RegType::kARM_GpW:
if (rId == Gp::kIdZr)
return sb.append("wzr");
if (rId == Gp::kIdSp)
return sb.append("wsp");
letter = 'w';
break;
case RegType::kARM_GpX:
if (rId == Gp::kIdZr)
return sb.append("xzr");
if (rId == Gp::kIdSp)
return sb.append("sp");
letter = 'x';
break;
case RegType::kARM_VecB:
case RegType::kARM_VecH:
case RegType::kARM_VecS:
case RegType::kARM_VecD:
case RegType::kARM_VecV:
letter = bhsdq[uint32_t(regType) - uint32_t(RegType::kARM_VecB)];
if (elementType)
letter = 'v';
break;
default:
ASMJIT_PROPAGATE(sb.appendFormat("<Reg-%u>?$u", uint32_t(regType), rId));
break;
}
if (letter)
ASMJIT_PROPAGATE(sb.appendFormat("%c%u", letter, rId));
}
if (elementType) {
char elementLetter = '\0';
uint32_t elementCount = 0;
switch (elementType) {
case Vec::kElementTypeB:
elementLetter = 'b';
elementCount = 16;
break;
case Vec::kElementTypeH:
elementLetter = 'h';
elementCount = 8;
break;
case Vec::kElementTypeS:
elementLetter = 's';
elementCount = 4;
break;
case Vec::kElementTypeD:
elementLetter = 'd';
elementCount = 2;
break;
default:
return sb.append(".<Unknown>");
}
if (elementLetter) {
if (elementIndex == 0xFFFFFFFFu) {
if (regType == RegType::kARM_VecD)
elementCount /= 2u;
ASMJIT_PROPAGATE(sb.appendFormat(".%u%c", elementCount, elementLetter));
}
else {
ASMJIT_PROPAGATE(sb.appendFormat(".%c[%u]", elementLetter, elementIndex));
}
}
}
return kErrorOk;
}
// a64::FormatterInternal - Format Operand
// =======================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
const Operand_& op) noexcept {
if (op.isReg()) {
const BaseReg& reg = op.as<BaseReg>();
uint32_t elementType = op.as<Vec>().elementType();
uint32_t elementIndex = op.as<Vec>().elementIndex();
if (!op.as<Vec>().hasElementIndex())
elementIndex = 0xFFFFFFFFu;
return formatRegister(sb, flags, emitter, arch, reg.type(), reg.id(), elementType, elementIndex);
}
if (op.isMem()) {
const Mem& m = op.as<Mem>();
ASMJIT_PROPAGATE(sb.append('['));
if (m.hasBase()) {
if (m.hasBaseLabel()) {
ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId()));
}
else {
FormatFlags modifiedFlags = flags;
if (m.isRegHome()) {
ASMJIT_PROPAGATE(sb.append('&'));
modifiedFlags &= ~FormatFlags::kRegCasts;
}
ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId()));
}
}
else {
// ARM really requires base.
if (m.hasIndex() || m.hasOffset()) {
ASMJIT_PROPAGATE(sb.append("<None>"));
}
}
// The post index makes it look like there was another operand, but it's
// still the part of AsmJit's `arm::Mem` operand so it's consistent with
// other architectures.
if (m.isPostIndex())
ASMJIT_PROPAGATE(sb.append(']'));
if (m.hasIndex()) {
ASMJIT_PROPAGATE(sb.append(", "));
ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId()));
}
if (m.hasOffset()) {
ASMJIT_PROPAGATE(sb.append(", "));
int64_t off = int64_t(m.offset());
uint32_t base = 10;
if (Support::test(flags, FormatFlags::kHexOffsets) && uint64_t(off) > 9)
base = 16;
if (base == 10) {
ASMJIT_PROPAGATE(sb.appendInt(off, base));
}
else {
ASMJIT_PROPAGATE(sb.append("0x"));
ASMJIT_PROPAGATE(sb.appendUInt(uint64_t(off), base));
}
}
if (m.hasShift()) {
ASMJIT_PROPAGATE(sb.append(' '));
if (!m.isPreOrPost())
ASMJIT_PROPAGATE(formatShiftOp(sb, (ShiftOp)m.predicate()));
ASMJIT_PROPAGATE(sb.appendFormat(" %u", m.shift()));
}
if (!m.isPostIndex())
ASMJIT_PROPAGATE(sb.append(']'));
if (m.isPreIndex())
ASMJIT_PROPAGATE(sb.append('!'));
return kErrorOk;
}
if (op.isImm()) {
const Imm& i = op.as<Imm>();
int64_t val = i.value();
if (Support::test(flags, FormatFlags::kHexImms) && uint64_t(val) > 9) {
ASMJIT_PROPAGATE(sb.append("0x"));
return sb.appendUInt(uint64_t(val), 16);
}
else {
return sb.appendInt(val, 10);
}
}
if (op.isLabel()) {
return Formatter::formatLabel(sb, flags, emitter, op.id());
}
return sb.append("<None>");
}
// a64::FormatterInternal - Format Instruction
// ===========================================

View File

@@ -24,23 +24,6 @@ namespace FormatterInternal {
using namespace arm::FormatterInternal;
Error ASMJIT_CDECL formatRegister(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
RegType regType,
uint32_t regId,
uint32_t elementType = 0,
uint32_t elementIndex = 0xFFFFFFFFu) noexcept;
Error ASMJIT_CDECL formatOperand(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
const Operand_& op) noexcept;
Error ASMJIT_CDECL formatInstruction(
String& sb,
FormatFlags flags,

View File

@@ -1417,9 +1417,12 @@ namespace SysReg {
kID_AA64DFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0101, 0b001), // RO
kID_AA64ISAR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0110, 0b000), // RO
kID_AA64ISAR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0110, 0b001), // RO
kID_AA64ISAR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0110, 0b010), // RO
kID_AA64MMFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b000), // RO
kID_AA64MMFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b001), // RO
kID_AA64MMFR2_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b010), // RO
kID_AA64MMFR3_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b011), // RO
kID_AA64MMFR4_EL1 = encode(0b11, 0b000, 0b0000, 0b0111, 0b100), // RO
kID_AA64PFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b000), // RO
kID_AA64PFR1_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b001), // RO
kID_AA64ZFR0_EL1 = encode(0b11, 0b000, 0b0000, 0b0100, 0b100), // RO

View File

@@ -26,78 +26,145 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
// @EnumStringBegin{"enum": "CpuFeatures::ARM", "output": "sFeature", "strip": "k"}@
static const char sFeatureString[] =
"None\0"
"THUMB\0"
"THUMBv2\0"
"ARMv6\0"
"ARMv7\0"
"ARMv8a\0"
"ARMv8_1a\0"
"ARMv8_2a\0"
"ARMv8_3a\0"
"ARMv8_4a\0"
"ARMv8_5a\0"
"ARMv8_6a\0"
"ARMv8_7a\0"
"VFPv2\0"
"VFPv3\0"
"VFPv4\0"
"VFP_D32\0"
"THUMB\0"
"THUMBv2\0"
"AES\0"
"ALTNZCV\0"
"AFP\0"
"ASIMD\0"
"BF16\0"
"BTI\0"
"CCIDX\0"
"CHK\0"
"CLRBHB\0"
"CPUID\0"
"CRC32\0"
"CSSC\0"
"D128\0"
"DGH\0"
"DIT\0"
"DOTPROD\0"
"DPB\0"
"DPB2\0"
"EBF16\0"
"ECV\0"
"EDSP\0"
"FCMA\0"
"FJCVTZS\0"
"FGT\0"
"FGT2\0"
"FHM\0"
"FLAGM\0"
"FLAGM2\0"
"FMAC\0"
"FP\0"
"FP16\0"
"FP16CONV\0"
"FP16FML\0"
"FP16FULL\0"
"FRINT\0"
"FRINTTS\0"
"GCS\0"
"HBC\0"
"HCX\0"
"I8MM\0"
"IDIVA\0"
"IDIVT\0"
"JSCVT\0"
"LOR\0"
"LRCPC\0"
"LRCPC2\0"
"LRCPC3\0"
"LS64\0"
"LS64_ACCDATA\0"
"LS64_V\0"
"LSE\0"
"LSE128\0"
"LSE2\0"
"MOPS\0"
"MPAM\0"
"MTE\0"
"RCPC_IMMO\0"
"RDM\0"
"MTE2\0"
"MTE3\0"
"MTE4\0"
"NMI\0"
"NV\0"
"NV2\0"
"PAN\0"
"PAN2\0"
"PAN3\0"
"PAUTH\0"
"PMU\0"
"PMULL\0"
"PRFMSLC\0"
"RAS\0"
"RAS1_1\0"
"RAS2\0"
"RDM\0"
"RME\0"
"RNG\0"
"RNG_TRAP\0"
"RPRES\0"
"RPRFM\0"
"SB\0"
"SHA1\0"
"SHA2\0"
"SHA256\0"
"SHA3\0"
"SHA512\0"
"SM3\0"
"SM4\0"
"SME\0"
"SME2\0"
"SME2_1\0"
"SME_B16B16\0"
"SME_B16F32\0"
"SME_BI32I32\0"
"SME_F16F16\0"
"SME_F16F32\0"
"SME_F32F32\0"
"SME_F64F64\0"
"SME_FA64\0"
"SME_I16I32\0"
"SME_I16I64\0"
"SME_I8I32\0"
"SPECRES\0"
"SPECRES2\0"
"SSBS\0"
"SSBS2\0"
"SVE\0"
"SVE2\0"
"SVE2_1\0"
"SVE_AES\0"
"SVE_B16B16\0"
"SVE_BF16\0"
"SVE_BITPERM\0"
"SVE_EBF16\0"
"SVE_F32MM\0"
"SVE_F64MM\0"
"SVE_I8MM\0"
"SVE_PMULL\0"
"SVE2\0"
"SVE2_AES\0"
"SVE2_BITPERM\0"
"SVE2_SHA3\0"
"SVE2_SM4\0"
"SVE_PMULL128\0"
"SVE_SHA3\0"
"SVE_SM4\0"
"SYSINSTR128\0"
"SYSREG128\0"
"THE\0"
"TME\0"
"TRF\0"
"UAO\0"
"VFP_D32\0"
"VHE\0"
"WFXT\0"
"XS\0"
"<Unknown>\0";
static const uint16_t sFeatureIndex[] = {
0, 5, 11, 19, 25, 31, 38, 47, 56, 65, 74, 83, 92, 101, 107, 113, 119, 127,
131, 139, 145, 150, 154, 160, 166, 170, 174, 182, 187, 192, 200, 206, 215,
223, 232, 238, 243, 249, 255, 259, 263, 273, 277, 281, 287, 291, 294, 299,
304, 309, 316, 320, 324, 329, 333, 342, 352, 362, 371, 381, 386, 395, 408,
418, 427, 431
0, 5, 11, 17, 24, 30, 38, 42, 46, 52, 57, 61, 67, 71, 78, 84, 90, 95, 100,
104, 108, 116, 120, 125, 131, 135, 140, 145, 149, 154, 158, 164, 171, 176,
179, 184, 193, 201, 205, 209, 213, 218, 224, 230, 236, 240, 246, 253, 260,
265, 278, 285, 289, 296, 301, 306, 311, 315, 320, 325, 330, 334, 337, 341,
345, 350, 355, 361, 365, 371, 379, 383, 390, 395, 399, 403, 407, 416, 422,
428, 431, 436, 443, 448, 455, 459, 463, 467, 472, 479, 490, 501, 513, 524,
535, 546, 557, 566, 577, 588, 598, 606, 615, 620, 626, 630, 635, 642, 650,
661, 670, 682, 692, 702, 712, 721, 734, 743, 751, 763, 773, 777, 781, 785,
789, 797, 801, 806, 809
};
// @EnumStringEnd@
@@ -138,6 +205,267 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatShiftOp(String& sb, ShiftOp shi
return sb.append(str);
}
// arm::FormatterInternal - Format Register
// ========================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
RegType regType,
uint32_t rId,
uint32_t elementType,
uint32_t elementIndex) noexcept {
DebugUtils::unused(flags);
DebugUtils::unused(arch);
static const char bhsdq[] = "bhsdq";
bool virtRegFormatted = false;
#ifndef ASMJIT_NO_COMPILER
if (Operand::isVirtId(rId)) {
if (emitter && emitter->isCompiler()) {
const BaseCompiler* cc = static_cast<const BaseCompiler*>(emitter);
if (cc->isVirtIdValid(rId)) {
VirtReg* vReg = cc->virtRegById(rId);
ASMJIT_ASSERT(vReg != nullptr);
const char* name = vReg->name();
if (name && name[0] != '\0')
ASMJIT_PROPAGATE(sb.append(name));
else
ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId))));
virtRegFormatted = true;
}
}
}
#else
DebugUtils::unused(emitter, flags);
#endif
if (!virtRegFormatted) {
char letter = '\0';
switch (regType) {
case RegType::kARM_VecB:
case RegType::kARM_VecH:
case RegType::kARM_VecS:
case RegType::kARM_VecD:
case RegType::kARM_VecV:
letter = bhsdq[uint32_t(regType) - uint32_t(RegType::kARM_VecB)];
if (elementType)
letter = 'v';
break;
case RegType::kARM_GpW:
if (Environment::is64Bit(arch)) {
letter = 'w';
if (rId == Gp::kIdZr)
return sb.append("wzr", 3);
if (rId == Gp::kIdSp)
return sb.append("wsp", 3);
}
else {
letter = 'r';
if (rId == 13)
return sb.append("sp", 2);
if (rId == 14)
return sb.append("lr", 2);
if (rId == 15)
return sb.append("pc", 2);
}
break;
case RegType::kARM_GpX:
if (Environment::is64Bit(arch)) {
if (rId == Gp::kIdZr)
return sb.append("xzr", 3);
if (rId == Gp::kIdSp)
return sb.append("sp", 2);
letter = 'x';
break;
}
// X registers are undefined in 32-bit mode.
ASMJIT_FALLTHROUGH;
default:
ASMJIT_PROPAGATE(sb.appendFormat("<Reg-%u>?$u", uint32_t(regType), rId));
break;
}
if (letter)
ASMJIT_PROPAGATE(sb.appendFormat("%c%u", letter, rId));
}
if (elementType) {
char elementLetter = '\0';
uint32_t elementCount = 0;
switch (elementType) {
case Vec::kElementTypeB:
elementLetter = 'b';
elementCount = 16;
break;
case Vec::kElementTypeH:
elementLetter = 'h';
elementCount = 8;
break;
case Vec::kElementTypeS:
elementLetter = 's';
elementCount = 4;
break;
case Vec::kElementTypeD:
elementLetter = 'd';
elementCount = 2;
break;
default:
return sb.append(".<Unknown>");
}
if (elementLetter) {
if (elementIndex == 0xFFFFFFFFu) {
if (regType == RegType::kARM_VecD)
elementCount /= 2u;
ASMJIT_PROPAGATE(sb.appendFormat(".%u%c", elementCount, elementLetter));
}
else {
ASMJIT_PROPAGATE(sb.appendFormat(".%c[%u]", elementLetter, elementIndex));
}
}
}
else if (elementIndex != 0xFFFFFFFFu) {
// This should only be used by AArch32 - AArch64 requires an additional elementType in index[].
ASMJIT_PROPAGATE(sb.appendFormat("[%u]", elementIndex));
}
return kErrorOk;
}
// a64::FormatterInternal - Format Operand
// =======================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
const Operand_& op) noexcept {
if (op.isReg()) {
const BaseReg& reg = op.as<BaseReg>();
uint32_t elementType = op.as<Vec>().elementType();
uint32_t elementIndex = op.as<Vec>().elementIndex();
if (!op.as<Vec>().hasElementIndex())
elementIndex = 0xFFFFFFFFu;
return formatRegister(sb, flags, emitter, arch, reg.type(), reg.id(), elementType, elementIndex);
}
if (op.isMem()) {
const Mem& m = op.as<Mem>();
ASMJIT_PROPAGATE(sb.append('['));
if (m.hasBase()) {
if (m.hasBaseLabel()) {
ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId()));
}
else {
FormatFlags modifiedFlags = flags;
if (m.isRegHome()) {
ASMJIT_PROPAGATE(sb.append('&'));
modifiedFlags &= ~FormatFlags::kRegCasts;
}
ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId()));
}
}
else {
// ARM really requires base.
if (m.hasIndex() || m.hasOffset()) {
ASMJIT_PROPAGATE(sb.append("<None>"));
}
}
// The post index makes it look like there was another operand, but it's
// still the part of AsmJit's `arm::Mem` operand so it's consistent with
// other architectures.
if (m.isPostIndex())
ASMJIT_PROPAGATE(sb.append(']'));
if (m.hasIndex()) {
ASMJIT_PROPAGATE(sb.append(", "));
ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId()));
}
if (m.hasOffset()) {
ASMJIT_PROPAGATE(sb.append(", "));
int64_t off = int64_t(m.offset());
uint32_t base = 10;
if (Support::test(flags, FormatFlags::kHexOffsets) && uint64_t(off) > 9)
base = 16;
if (base == 10) {
ASMJIT_PROPAGATE(sb.appendInt(off, base));
}
else {
ASMJIT_PROPAGATE(sb.append("0x"));
ASMJIT_PROPAGATE(sb.appendUInt(uint64_t(off), base));
}
}
if (m.hasShift()) {
ASMJIT_PROPAGATE(sb.append(' '));
if (!m.isPreOrPost())
ASMJIT_PROPAGATE(formatShiftOp(sb, (ShiftOp)m.predicate()));
ASMJIT_PROPAGATE(sb.appendFormat(" %u", m.shift()));
}
if (!m.isPostIndex())
ASMJIT_PROPAGATE(sb.append(']'));
if (m.isPreIndex())
ASMJIT_PROPAGATE(sb.append('!'));
return kErrorOk;
}
if (op.isImm()) {
const Imm& i = op.as<Imm>();
int64_t val = i.value();
if (Support::test(flags, FormatFlags::kHexImms) && uint64_t(val) > 9) {
ASMJIT_PROPAGATE(sb.append("0x"));
return sb.appendUInt(uint64_t(val), 16);
}
else {
return sb.appendInt(val, 10);
}
}
if (op.isLabel()) {
return Formatter::formatLabel(sb, flags, emitter, op.id());
}
return sb.append("<None>");
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_LOGGING

View File

@@ -33,6 +33,23 @@ Error ASMJIT_CDECL formatShiftOp(
String& sb,
ShiftOp shiftOp) noexcept;
Error ASMJIT_CDECL formatRegister(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
RegType regType,
uint32_t rId,
uint32_t elementType = 0,
uint32_t elementIndex = 0xFFFFFFFF) noexcept;
Error ASMJIT_CDECL formatOperand(
String& sb,
FormatFlags flags,
const BaseEmitter* emitter,
Arch arch,
const Operand_& op) noexcept;
} // {FormatterInternal}
//! \}

View File

@@ -178,7 +178,7 @@ public:
kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
};
//! Element type.
//! Element type (AArch64 only).
enum ElementType : uint32_t {
//! No element type specified.
kElementTypeNone = 0,
@@ -258,15 +258,15 @@ public:
return Vec((signature() & ~kSignatureRegElementIndexMask) | (elementIndex << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id());
}
//! Cast this register to an 8-bit B register (scalar).
//! Cast this register to an 8-bit B register (AArch64 only).
inline VecB b() const noexcept;
//! Cast this register to a 16-bit H register (scalar).
//! Cast this register to a 16-bit H register (AArch64 only).
inline VecH h() const noexcept;
//! Cast this register to a 32-bit S register (scalar).
//! Cast this register to a 32-bit S register.
inline VecS s() const noexcept;
//! Cast this register to a 64-bit D register (scalar).
//! Cast this register to a 64-bit D register.
inline VecD d() const noexcept;
//! Cast this register to a 128-bit Q register (scalar).
//! Cast this register to a 128-bit Q register.
inline VecV q() const noexcept;
//! Cast this register to a 128-bit V register.
inline VecV v() const noexcept;
@@ -553,37 +553,42 @@ public:
//! \}
};
//! Creates `[base.reg, offset]` memory operand (offset mode).
//! Creates `[base, offset]` memory operand (offset mode).
static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
//! Creates `[base.reg, offset]!` memory operand (pre-index mode).
//! Creates `[base, offset]!` memory operand (pre-index mode).
static inline constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
}
//! Creates `[base.reg], offset` memory operand (post-index mode).
//! Creates `[base], offset` memory operand (post-index mode).
static inline constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
}
//! Creates `[base.reg, index]` memory operand.
//! Creates `[base, index]` memory operand.
static inline constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
return Mem(base, index);
}
//! Creates `[base.reg], index` memory operand (post-index mode).
//! Creates `[base, index]!` memory operand (pre-index mode).
static inline constexpr Mem ptr_pre(const Gp& base, const Gp& index) noexcept {
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
}
//! Creates `[base], index` memory operand (post-index mode).
static inline constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
}
//! Creates `[base.reg, index, SHIFT_OP #shift]` memory operand.
//! Creates `[base, index, SHIFT_OP #shift]` memory operand.
static inline constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
return Mem(base, index, shift);
}
//! Creates `[base + offset]` memory operand.
//! Creates `[base, offset]` memory operand.
static inline constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
@@ -600,8 +605,8 @@ static inline constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
//!
//! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing.
//! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it
//! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit support it so it
//! can assemble it back.
//! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit supports it to
//! make it possible to assemble such output back.
static inline constexpr Mem ptr(uint64_t base) noexcept { return Mem(base); }
//! \}

View File

@@ -3,20 +3,20 @@
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_ARM_A64UTILS_H_INCLUDED
#define ASMJIT_ARM_A64UTILS_H_INCLUDED
#ifndef ASMJIT_ARM_ARMUTILS_H_INCLUDED
#define ASMJIT_ARM_ARMUTILS_H_INCLUDED
#include "../arm/a64globals.h"
#include "../arm/armglobals.h"
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
//! \addtogroup asmjit_a64
//! \addtogroup asmjit_arm
//! \{
//! Public utilities and helpers for targeting AArch64 architecture.
//! Public utilities and helpers for targeting AArch32 and AArch64 architectures.
namespace Utils {
//! Decomposed fields of a logical immediate value (AArch64).
//! Decomposed fields of a logical immediate value.
struct LogicalImm {
uint32_t n;
uint32_t s;
@@ -41,7 +41,7 @@ struct LogicalImm {
//! +---+--------+--------+------+
//! ```
ASMJIT_MAYBE_UNUSED
static bool encodeLogicalImm(uint64_t imm, uint32_t width, a64::Utils::LogicalImm* out) noexcept {
static bool encodeLogicalImm(uint64_t imm, uint32_t width, LogicalImm* out) noexcept {
// Determine the element width, which must be 2, 4, 8, 16, 32, or 64 bits.
do {
width /= 2;
@@ -89,7 +89,7 @@ static bool encodeLogicalImm(uint64_t imm, uint32_t width, a64::Utils::LogicalIm
//! width of the operation, and must be either 32 or 64. This function can be used to test whether an immediate
//! value can be used with AND, ANDS, BIC, BICS, EON, EOR, ORN, and ORR instruction.
ASMJIT_MAYBE_UNUSED
static inline bool isLogicalImm(uint64_t imm, uint32_t width) noexcept {
static ASMJIT_FORCE_INLINE bool isLogicalImm(uint64_t imm, uint32_t width) noexcept {
LogicalImm dummy;
return encodeLogicalImm(imm, width, &dummy);
}
@@ -98,15 +98,22 @@ static inline bool isLogicalImm(uint64_t imm, uint32_t width) noexcept {
//! 0x00 or 0xFF. Some ARM instructions accept immediates that form a byte-mask and this function can be used to
//! verify that the immediate is encodable before using the value.
template<typename T>
static inline bool isByteMaskImm8(const T& imm) noexcept {
static ASMJIT_FORCE_INLINE bool isByteMaskImm8(const T& imm) noexcept {
constexpr T kMask = T(0x0101010101010101 & Support::allOnes<T>());
return imm == (imm & kMask) * T(255);
}
// [.......A|B.......|.......C|D.......|.......E|F.......|.......G|H.......]
static ASMJIT_FORCE_INLINE uint32_t encodeImm64ByteMaskToImm8(uint64_t imm) noexcept {
return uint32_t(((imm >> (7 - 0)) & 0b00000011) | // [.......G|H.......]
((imm >> (23 - 2)) & 0b00001100) | // [.......E|F.......]
((imm >> (39 - 4)) & 0b00110000) | // [.......C|D.......]
((imm >> (55 - 6)) & 0b11000000)); // [.......A|B.......]
}
//! \cond
//! A generic implementation that checjs whether a floating point value can be converted to ARM Imm8.
template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
static inline bool isFPImm8Generic(T val) noexcept {
static ASMJIT_FORCE_INLINE bool isFPImm8Generic(T val) noexcept {
constexpr uint32_t kAllBsMask = Support::lsbMask<uint32_t>(kNumBBits);
constexpr uint32_t kB0Pattern = Support::bitMask(kNumBBits - 1);
constexpr uint32_t kB1Pattern = kAllBsMask ^ kB0Pattern;
@@ -127,7 +134,7 @@ static inline bool isFPImm8Generic(T val) noexcept {
//! ```
//! [aBbbcdef|gh000000]
//! ```
static inline bool isFP16Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 3, 6, 6>(val); }
static ASMJIT_FORCE_INLINE bool isFP16Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 3, 6, 6>(val); }
//! Returns true if the given single precision floating point `val` can be encoded as ARM IMM8 value, which represents
//! a limited set of floating point immediate values, which can be used with FMOV instruction.
@@ -137,9 +144,9 @@ static inline bool isFP16Imm8(uint32_t val) noexcept { return isFPImm8Generic<ui
//! ```
//! [aBbbbbbc|defgh000|00000000|00000000]
//! ```
static inline bool isFP32Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 6, 6, 19>(val); }
static ASMJIT_FORCE_INLINE bool isFP32Imm8(uint32_t val) noexcept { return isFPImm8Generic<uint32_t, 6, 6, 19>(val); }
//! \overload
static inline bool isFP32Imm8(float val) noexcept { return isFP32Imm8(Support::bitCast<uint32_t>(val)); }
static ASMJIT_FORCE_INLINE bool isFP32Imm8(float val) noexcept { return isFP32Imm8(Support::bitCast<uint32_t>(val)); }
//! Returns true if the given double precision floating point `val` can be encoded as ARM IMM8 value, which represents
//! a limited set of floating point immediate values, which can be used with FMOV instruction.
@@ -149,13 +156,13 @@ static inline bool isFP32Imm8(float val) noexcept { return isFP32Imm8(Support::b
//! ```
//! [aBbbbbbb|bbcdefgh|00000000|00000000|00000000|00000000|00000000|00000000]
//! ```
static inline bool isFP64Imm8(uint64_t val) noexcept { return isFPImm8Generic<uint64_t, 9, 6, 48>(val); }
static ASMJIT_FORCE_INLINE bool isFP64Imm8(uint64_t val) noexcept { return isFPImm8Generic<uint64_t, 9, 6, 48>(val); }
//! \overload
static inline bool isFP64Imm8(double val) noexcept { return isFP64Imm8(Support::bitCast<uint64_t>(val)); }
static ASMJIT_FORCE_INLINE bool isFP64Imm8(double val) noexcept { return isFP64Imm8(Support::bitCast<uint64_t>(val)); }
//! \cond
template<typename T, uint32_t kNumBBits, uint32_t kNumCDEFGHBits, uint32_t kNumZeroBits>
static inline uint32_t encodeFPToImm8Generic(T val) noexcept {
static ASMJIT_FORCE_INLINE uint32_t encodeFPToImm8Generic(T val) noexcept {
uint32_t bits = uint32_t(val >> kNumZeroBits);
return ((bits >> (kNumBBits + kNumCDEFGHBits - 7)) & 0x80u) | (bits & 0x7F);
}
@@ -165,9 +172,9 @@ static inline uint32_t encodeFPToImm8Generic(T val) noexcept {
//!
//! \note This function expects that `isFP64Imm8(val) == true` so it doesn't perform any checks of the value and just
//! rearranges some bits into Imm8 order.
static inline uint32_t encodeFP64ToImm8(uint64_t val) noexcept { return encodeFPToImm8Generic<uint64_t, 9, 6, 48>(val); }
static ASMJIT_FORCE_INLINE uint32_t encodeFP64ToImm8(uint64_t val) noexcept { return encodeFPToImm8Generic<uint64_t, 9, 6, 48>(val); }
//! \overload
static inline uint32_t encodeFP64ToImm8(double val) noexcept { return encodeFP64ToImm8(Support::bitCast<uint64_t>(val)); }
static ASMJIT_FORCE_INLINE uint32_t encodeFP64ToImm8(double val) noexcept { return encodeFP64ToImm8(Support::bitCast<uint64_t>(val)); }
} // {Utils}
@@ -175,5 +182,5 @@ static inline uint32_t encodeFP64ToImm8(double val) noexcept { return encodeFP64
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A64UTILS_H_INCLUDED
#endif // ASMJIT_ARM_ARMUTILS_H_INCLUDED

View File

@@ -82,9 +82,6 @@ namespace asmjit {
//! Disables X86/X64 backends.
#define ASMJIT_NO_X86
//! Disables AArch32 backends (both ARM and Thumb).
#define ASMJIT_NO_AARCH32
//! Disables AArch64 backend.
#define ASMJIT_NO_AARCH64

View File

@@ -103,6 +103,8 @@ enum class DataType : uint32_t {
kF64 = 12,
//! 8-bit polynomial.
kP8 = 13,
//! 16-bit BF16 floating point.
kBF16 = 14,
//! 64-bit polynomial.
kP64 = 15,

File diff suppressed because it is too large Load Diff

View File

@@ -88,12 +88,22 @@ public:
return bool((_bits[idx] >> bit) & 0x1);
}
template<typename FeatureId>
ASMJIT_FORCE_INLINE bool hasAny(const FeatureId& featureId) const noexcept {
return has(featureId);
}
template<typename FeatureId, typename... Args>
ASMJIT_FORCE_INLINE bool hasAny(const FeatureId& featureId, Args&&... otherFeatureIds) const noexcept {
return bool(unsigned(has(featureId)) | unsigned(hasAny(std::forward<Args>(otherFeatureIds)...)));
}
//! Tests whether all features as defined by `other` are present.
ASMJIT_FORCE_INLINE bool hasAll(const Data& other) const noexcept {
uint32_t result = 1;
for (uint32_t i = 0; i < kNumBitWords; i++)
if ((_bits[i] & other._bits[i]) != other._bits[i])
return false;
return true;
result &= uint32_t((_bits[i] & other._bits[i]) == other._bits[i]);
return bool(result);
}
//! \}
@@ -169,38 +179,41 @@ public:
kMT, //!< CPU has multi-threading capabilities.
kNX, //!< CPU has Not-Execute-Bit aka DEP (data-execution prevention).
k3DNOW, //!< CPU has 3DNOW (3DNOW base instructions) [AMD].
k3DNOW2, //!< CPU has 3DNOW2 (enhanced 3DNOW) [AMD].
k3DNOW, //!< CPU has 3DNOW (3DNOW base instructions) {AMD} (deprecated).
k3DNOW2, //!< CPU has 3DNOW2 (enhanced 3DNOW) {AMD} (deprecated).
kADX, //!< CPU has ADX (multi-precision add-carry instruction extensions).
kAESNI, //!< CPU has AESNI (AES encode/decode instructions).
kALTMOVCR8, //!< CPU has LOCK MOV R<->CR0 (supports `MOV R<->CR8` via `LOCK MOV R<->CR0` in 32-bit mode) [AMD].
kAMX_BF16, //!< CPU has AMX_BF16 (advanced matrix extensions - BF16 instructions).
kAMX_FP16, //!< CPU has AMX_FP16 (advanced matrix extensions - FP16 instructions).
kAMX_INT8, //!< CPU has AMX_INT8 (advanced matrix extensions - INT8 instructions).
kALTMOVCR8, //!< CPU has LOCK MOV R<->CR0 (supports `MOV R<->CR8` via `LOCK MOV R<->CR0` in 32-bit mode) {AMD}.
kAMX_BF16, //!< CPU has AMX_BF16 (AMX-BF16 instructions).
kAMX_COMPLEX, //!< CPU has AMX_COMPLEX (AMX-COMPLEX instructions).
kAMX_FP16, //!< CPU has AMX_FP16 (AMX-FP16 instructions).
kAMX_INT8, //!< CPU has AMX_INT8 (AMX-INT8 instructions).
kAMX_TILE, //!< CPU has AMX_TILE (advanced matrix extensions).
kAPX_F, //!< CPU has APX_F (advanced performance extensions - 32 GP registers, REX2 prefix, ...) {X86_64}.
kAVX, //!< CPU has AVX (advanced vector extensions).
kAVX2, //!< CPU has AVX2 (advanced vector extensions 2).
kAVX512_4FMAPS, //!< CPU has AVX512_FMAPS (FMA packed single).
kAVX512_4VNNIW, //!< CPU has AVX512_VNNIW (vector NN instructions word variable precision).
kAVX512_BF16, //!< CPU has AVX512_BF16 (BFLOAT16 support instruction).
kAVX512_BITALG, //!< CPU has AVX512_BITALG (VPOPCNT[B|W], VPSHUFBITQMB).
kAVX512_BW, //!< CPU has AVX512_BW (packed BYTE|WORD).
kAVX512_CDI, //!< CPU has AVX512_CDI (conflict detection).
kAVX512_DQ, //!< CPU has AVX512_DQ (packed DWORD|QWORD).
kAVX512_ERI, //!< CPU has AVX512_ERI (exponential and reciprocal).
kAVX512_BF16, //!< CPU has AVX512_BF16 (AVX512 BFLOAT16 support instructions).
kAVX512_BITALG, //!< CPU has AVX512_BITALG (AVX512 VPOPCNT[B|W] and VPSHUFBITQMB instructions).
kAVX512_BW, //!< CPU has AVX512_BW (AVX512 integer BYTE|WORD instructions).
kAVX512_CD, //!< CPU has AVX512_CD (AVX512 conflict detection DWORD|QWORD instructions).
kAVX512_DQ, //!< CPU has AVX512_DQ (AVX512 integer DWORD|QWORD instructions).
kAVX512_ER, //!< CPU has AVX512_ER (AVX512 exponential and reciprocal instructions).
kAVX512_F, //!< CPU has AVX512_F (AVX512 foundation).
kAVX512_FP16, //!< CPU has AVX512_FP16 (FP16 extensions).
kAVX512_IFMA, //!< CPU has AVX512_IFMA (integer fused-multiply-add using 52-bit precision).
kAVX512_PFI, //!< CPU has AVX512_PFI (prefetch instructions).
kAVX512_VBMI, //!< CPU has AVX512_VBMI (vector byte manipulation).
kAVX512_VBMI2, //!< CPU has AVX512_VBMI2 (vector byte manipulation 2).
kAVX512_VL, //!< CPU has AVX512_VL (vector length extensions).
kAVX512_VNNI, //!< CPU has AVX512_VNNI (vector neural network instructions).
kAVX512_FP16, //!< CPU has AVX512_FP16 (AVX512 FP16 instructions).
kAVX512_IFMA, //!< CPU has AVX512_IFMA (AVX512 integer fused-multiply-add using 52-bit precision).
kAVX512_PF, //!< CPU has AVX512_PF (AVX512 prefetch instructions).
kAVX512_VBMI, //!< CPU has AVX512_VBMI (AVX152 vector byte manipulation instructions).
kAVX512_VBMI2, //!< CPU has AVX512_VBMI2 (AVX512 vector byte manipulation instructions v2).
kAVX512_VL, //!< CPU has AVX512_VL (AVX512 vector length extensions).
kAVX512_VNNI, //!< CPU has AVX512_VNNI (AVX512 vector neural network instructions).
kAVX512_VP2INTERSECT, //!< CPU has AVX512_VP2INTERSECT
kAVX512_VPOPCNTDQ, //!< CPU has AVX512_VPOPCNTDQ (VPOPCNT[D|Q] instructions).
kAVX_IFMA, //!< CPU has AVX_IFMA (VEX encoding of vpmadd52huq/vpmadd52luq).
kAVX512_VPOPCNTDQ, //!< CPU has AVX512_VPOPCNTDQ (AVX512 VPOPCNT[D|Q] instructions).
kAVX_IFMA, //!< CPU has AVX_IFMA (AVX/VEX encoding of vpmadd52huq/vpmadd52luq).
kAVX_NE_CONVERT, //!< CPU has AVX_NE_CONVERT.
kAVX_VNNI, //!< CPU has AVX_VNNI (VEX encoding of vpdpbusd/vpdpbusds/vpdpwssd/vpdpwssds).
kAVX_VNNI, //!< CPU has AVX_VNNI (AVX/VEX encoding of vpdpbusd/vpdpbusds/vpdpwssd/vpdpwssds).
kAVX_VNNI_INT16, //!< CPU has AVX_VNNI_INT16.
kAVX_VNNI_INT8, //!< CPU has AVX_VNNI_INT8.
kBMI, //!< CPU has BMI (bit manipulation instructions #1).
kBMI2, //!< CPU has BMI2 (bit manipulation instructions #2).
@@ -208,20 +221,20 @@ public:
kCET_SS, //!< CPU has CET-SS.
kCET_SSS, //!< CPU has CET-SSS.
kCLDEMOTE, //!< CPU has CLDEMOTE (cache line demote).
kCLFLUSH, //!< CPU has CLFUSH (Cache Line flush).
kCLFLUSHOPT, //!< CPU has CLFUSHOPT (Cache Line flush - optimized).
kCLFLUSH, //!< CPU has CLFUSH (cache Line flush).
kCLFLUSHOPT, //!< CPU has CLFUSHOPT (cache Line flush - optimized).
kCLWB, //!< CPU has CLWB.
kCLZERO, //!< CPU has CLZERO.
kCMOV, //!< CPU has CMOV (CMOV and FCMOV instructions).
kCMPCCXADD, //!< CPU has CMPCCXADD.
kCMPXCHG16B, //!< CPU has CMPXCHG16B (compare-exchange 16 bytes) [X86_64].
kCMPXCHG16B, //!< CPU has CMPXCHG16B (compare-exchange 16 bytes) {X86_64}.
kCMPXCHG8B, //!< CPU has CMPXCHG8B (compare-exchange 8 bytes).
kENCLV, //!< CPU has ENCLV.
kENQCMD, //!< CPU has ENQCMD (enqueue stores).
kERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
kF16C, //!< CPU has F16C.
kFMA, //!< CPU has FMA (fused-multiply-add 3 operand form).
kFMA4, //!< CPU has FMA4 (fused-multiply-add 4 operand form).
kF16C, //!< CPU has F16C (AVX FP16 conversion instructions).
kFMA, //!< CPU has FMA (AVX fused-multiply-add - 3 operand form).
kFMA4, //!< CPU has FMA4 (AVX fused-multiply-add - 4 operand form) (deprecated).
kFPU, //!< CPU has FPU (FPU support).
kFSGSBASE, //!< CPU has FSGSBASE.
kFSRM, //!< CPU has FSRM (fast short REP MOVSB).
@@ -230,18 +243,19 @@ public:
kFXSR, //!< CPU has FXSR (FXSAVE/FXRSTOR instructions).
kFXSROPT, //!< CPU has FXSROTP (FXSAVE/FXRSTOR is optimized).
kFZRM, //!< CPU has FZRM (fast zero-length REP MOVSB).
kGEODE, //!< CPU has GEODE extensions (3DNOW additions).
kGFNI, //!< CPU has GFNI (Galois field instructions).
kGEODE, //!< CPU has GEODE extensions (GEODE 3DNOW additions) (deprecated).
kGFNI, //!< CPU has GFNI (galois field instructions).
kHLE, //!< CPU has HLE.
kHRESET, //!< CPU has HRESET.
kI486, //!< CPU has I486 features (I486+ support).
kLAHFSAHF, //!< CPU has LAHF/SAHF (LAHF/SAHF in 64-bit mode) [X86_64].
kLAM, //!< CPU has LAM (linear address masking) [X86_64].
kLWP, //!< CPU has LWP (lightweight profiling) [AMD].
kINVLPGB, //!< CPU has INVLPGB.
kLAHFSAHF, //!< CPU has LAHF/SAHF (LAHF/SAHF in 64-bit mode) {X86_64}.
kLAM, //!< CPU has LAM (linear address masking) {X86_64}.
kLWP, //!< CPU has LWP (lightweight profiling) {AMD}.
kLZCNT, //!< CPU has LZCNT (LZCNT instruction).
kMCOMMIT, //!< CPU has MCOMMIT (MCOMMIT instruction).
kMMX, //!< CPU has MMX (MMX base instructions).
kMMX2, //!< CPU has MMX2 (MMX extensions or MMX2).
kMMX, //!< CPU has MMX (MMX base instructions) (deprecated).
kMMX2, //!< CPU has MMX2 (MMX2 extensions or initial SSE extensions) (deprecated).
kMONITOR, //!< CPU has MONITOR (MONITOR/MWAIT instructions).
kMONITORX, //!< CPU has MONITORX (MONITORX/MWAITX instructions).
kMOVBE, //!< CPU has MOVBE (move with byte-order swap).
@@ -260,40 +274,49 @@ public:
kPREFETCHW, //!< CPU has PREFETCHW.
kPREFETCHWT1, //!< CPU has PREFETCHWT1.
kPTWRITE, //!< CPU has PTWRITE.
kRAO_INT, //!< CPU has RAO_INT.
kRDPID, //!< CPU has RDPID.
kRDPRU, //!< CPU has RDPRU.
kRDRAND, //!< CPU has RDRAND.
kRDSEED, //!< CPU has RDSEED.
kRAO_INT, //!< CPU has RAO_INT (AADD, AAND, AOR, AXOR instructions).
kRMPQUERY, //!< CPU has RMPQUERY (RMPQUERY instruction).
kRDPID, //!< CPU has RDPID (RDPID instruction).
kRDPRU, //!< CPU has RDPRU (RDPRU instruction).
kRDRAND, //!< CPU has RDRAND (RDRAND instruction).
kRDSEED, //!< CPU has RDSEED (RDSEED instruction).
kRDTSC, //!< CPU has RDTSC.
kRDTSCP, //!< CPU has RDTSCP.
kRTM, //!< CPU has RTM.
kSEAM, //!< CPU has SEAM.
kSERIALIZE, //!< CPU has SERIALIZE.
kSEV, //!< CPU has SEV (secure encrypted virtualization).
kSEV_ES, //!< CPU has SEV_ES (SEV encrypted state).
kSEV_SNP, //!< CPU has SEV_SNP (SEV secure nested paging).
kSHA, //!< CPU has SHA (SHA-1 and SHA-256 instructions).
kSKINIT, //!< CPU has SKINIT (SKINIT/STGI instructions) [AMD].
kSHA512, //!< CPU has SHA512 (SHA-512 instructions).
kSKINIT, //!< CPU has SKINIT (SKINIT/STGI instructions) {AMD}.
kSM3, //!< CPU has SM3 (SM3 hash extensions).
kSM4, //!< CPU has SM4 (SM4 cipher extensions).
kSMAP, //!< CPU has SMAP (supervisor-mode access prevention).
kSME , //!< CPU has SME (secure memory encryption).
kSMEP, //!< CPU has SMEP (supervisor-mode execution prevention).
kSMX, //!< CPU has SMX (safer mode extensions).
kSNP, //!< CPU has SNP.
kSSE, //!< CPU has SSE.
kSSE2, //!< CPU has SSE2.
kSSE3, //!< CPU has SSE3.
kSSE4_1, //!< CPU has SSE4.1.
kSSE4_2, //!< CPU has SSE4.2.
kSSE4A, //!< CPU has SSE4A [AMD].
kSSSE3, //!< CPU has SSSE3.
kSVM, //!< CPU has SVM (virtualization) [AMD].
kTBM, //!< CPU has TBM (trailing bit manipulation) [AMD].
kSSE, //!< CPU has SSE (SSE instructions).
kSSE2, //!< CPU has SSE2 (SSE2 instructions).
kSSE3, //!< CPU has SSE3 (SSE3 instructions).
kSSE4_1, //!< CPU has SSE4.1 (SSE4.1 instructions).
kSSE4_2, //!< CPU has SSE4.2 (SSE4.2 instructions).
kSSE4A, //!< CPU has SSE4A (SSE4.A instructions) {AMD} (deprecated).
kSSSE3, //!< CPU has SSSE3 (SSSE3 instructions).
kSVM, //!< CPU has SVM (virtualization) {AMD}.
kTBM, //!< CPU has TBM (trailing bit manipulation) {AMD}.
kTSE, //!< CPU has TSE.
kTSX, //!< CPU has TSX.
kTSXLDTRK, //!< CPU has TSXLDTRK.
kUINTR, //!< CPU has UINTR (user interrupts).
kVAES, //!< CPU has VAES (vector AES 256|512 bit support).
kVMX, //!< CPU has VMX (virtualization) [INTEL].
kVMX, //!< CPU has VMX (virtualization) {INTEL}.
kVPCLMULQDQ, //!< CPU has VPCLMULQDQ (vector PCLMULQDQ 256|512-bit support).
kWAITPKG, //!< CPU has WAITPKG (UMONITOR, UMWAIT, TPAUSE).
kWBNOINVD, //!< CPU has WBNOINVD.
kWRMSRNS, //!< CPU has WRMSRNS.
kXOP, //!< CPU has XOP (XOP instructions) [AMD].
kXOP, //!< CPU has XOP (XOP instructions) {AMD} (deprecated).
kXSAVE, //!< CPU has XSAVE.
kXSAVEC, //!< CPU has XSAVEC.
kXSAVEOPT, //!< CPU has XSAVEOPT.
@@ -314,9 +337,11 @@ public:
ASMJIT_X86_FEATURE(AESNI)
ASMJIT_X86_FEATURE(ALTMOVCR8)
ASMJIT_X86_FEATURE(AMX_BF16)
ASMJIT_X86_FEATURE(AMX_COMPLEX)
ASMJIT_X86_FEATURE(AMX_FP16)
ASMJIT_X86_FEATURE(AMX_INT8)
ASMJIT_X86_FEATURE(AMX_TILE)
ASMJIT_X86_FEATURE(APX_F)
ASMJIT_X86_FEATURE(AVX)
ASMJIT_X86_FEATURE(AVX2)
ASMJIT_X86_FEATURE(AVX512_4FMAPS)
@@ -324,13 +349,13 @@ public:
ASMJIT_X86_FEATURE(AVX512_BF16)
ASMJIT_X86_FEATURE(AVX512_BITALG)
ASMJIT_X86_FEATURE(AVX512_BW)
ASMJIT_X86_FEATURE(AVX512_CDI)
ASMJIT_X86_FEATURE(AVX512_CD)
ASMJIT_X86_FEATURE(AVX512_DQ)
ASMJIT_X86_FEATURE(AVX512_ERI)
ASMJIT_X86_FEATURE(AVX512_ER)
ASMJIT_X86_FEATURE(AVX512_F)
ASMJIT_X86_FEATURE(AVX512_FP16)
ASMJIT_X86_FEATURE(AVX512_IFMA)
ASMJIT_X86_FEATURE(AVX512_PFI)
ASMJIT_X86_FEATURE(AVX512_PF)
ASMJIT_X86_FEATURE(AVX512_VBMI)
ASMJIT_X86_FEATURE(AVX512_VBMI2)
ASMJIT_X86_FEATURE(AVX512_VL)
@@ -340,6 +365,7 @@ public:
ASMJIT_X86_FEATURE(AVX_IFMA)
ASMJIT_X86_FEATURE(AVX_NE_CONVERT)
ASMJIT_X86_FEATURE(AVX_VNNI)
ASMJIT_X86_FEATURE(AVX_VNNI_INT16)
ASMJIT_X86_FEATURE(AVX_VNNI_INT8)
ASMJIT_X86_FEATURE(BMI)
ASMJIT_X86_FEATURE(BMI2)
@@ -373,6 +399,7 @@ public:
ASMJIT_X86_FEATURE(HLE)
ASMJIT_X86_FEATURE(HRESET)
ASMJIT_X86_FEATURE(I486)
ASMJIT_X86_FEATURE(INVLPGB)
ASMJIT_X86_FEATURE(LAHFSAHF)
ASMJIT_X86_FEATURE(LAM)
ASMJIT_X86_FEATURE(LWP)
@@ -399,6 +426,7 @@ public:
ASMJIT_X86_FEATURE(PREFETCHWT1)
ASMJIT_X86_FEATURE(PTWRITE)
ASMJIT_X86_FEATURE(RAO_INT)
ASMJIT_X86_FEATURE(RMPQUERY)
ASMJIT_X86_FEATURE(RDPID)
ASMJIT_X86_FEATURE(RDPRU)
ASMJIT_X86_FEATURE(RDRAND)
@@ -406,13 +434,16 @@ public:
ASMJIT_X86_FEATURE(RDTSC)
ASMJIT_X86_FEATURE(RDTSCP)
ASMJIT_X86_FEATURE(RTM)
ASMJIT_X86_FEATURE(SEAM)
ASMJIT_X86_FEATURE(SERIALIZE)
ASMJIT_X86_FEATURE(SEV)
ASMJIT_X86_FEATURE(SEV_ES)
ASMJIT_X86_FEATURE(SEV_SNP)
ASMJIT_X86_FEATURE(SHA)
ASMJIT_X86_FEATURE(SKINIT)
ASMJIT_X86_FEATURE(SMAP)
ASMJIT_X86_FEATURE(SMEP)
ASMJIT_X86_FEATURE(SMX)
ASMJIT_X86_FEATURE(SNP)
ASMJIT_X86_FEATURE(SSE)
ASMJIT_X86_FEATURE(SSE2)
ASMJIT_X86_FEATURE(SSE3)
@@ -422,6 +453,7 @@ public:
ASMJIT_X86_FEATURE(SSSE3)
ASMJIT_X86_FEATURE(SVM)
ASMJIT_X86_FEATURE(TBM)
ASMJIT_X86_FEATURE(TSE)
ASMJIT_X86_FEATURE(TSX)
ASMJIT_X86_FEATURE(TSXLDTRK)
ASMJIT_X86_FEATURE(UINTR)
@@ -441,81 +473,146 @@ public:
};
//! ARM specific features data.
//!
//! Naming reference:
//! - https://developer.arm.com/downloads/-/exploration-tools/feature-names-for-a-profile
struct ARM : public Data {
//! ARM CPU feature identifiers.
enum Id : uint8_t {
// @EnumValuesBegin{"enum": "CpuFeatures::ARM"}@
kNone = 0, //!< No feature (never set, used internally).
kTHUMB, //!< THUMB v1 ISA.
kTHUMBv2, //!< THUMB v2 ISA.
kARMv6, //!< ARMv6 ISA.
kARMv7, //!< ARMv7 ISA.
kARMv8a, //!< ARMv8-A ISA.
kARMv8_1a, //!< ARMv8.1-A ISA.
kARMv8_2a, //!< ARMv8.2-A ISA.
kARMv8_3a, //!< ARMv8.3-A ISA.
kARMv8_4a, //!< ARMv8.4-A ISA.
kARMv8_5a, //!< ARMv8.5-A ISA.
kARMv8_6a, //!< ARMv8.6-A ISA.
kARMv8_7a, //!< ARMv8.7-A ISA.
kARMv6, //!< CPU is at least ARMv6 {A32}.
kARMv7, //!< CPU is at least ARMv7 {A32}.
kARMv8a, //!< CPU is at least ARMv8A.
kTHUMB, //!< CPU has THUMB (16-bit THUMB encoding) {A32}.
kTHUMBv2, //!< CPU has THUMBv2 (32-bit THUMB encoding) {A32}.
kVFPv2, //!< CPU has VFPv2 instruction set.
kVFPv3, //!< CPU has VFPv3 instruction set.
kVFPv4, //!< CPU has VFPv4 instruction set.
kVFP_D32, //!< CPU has 32 VFP-D (64-bit) registers.
kAES, //!< CPU has AES (AArch64 only).
kALTNZCV, //!< CPU has ALTNZCV (AArch64 only).
kASIMD, //!< CPU has Advanced SIMD (NEON on ARM/THUMB).
kBF16, //!< CPU has BF16 (AArch64 only).
kAES, //!< CPU has AES (ASIMD AES instructions).
kAFP, //!< CPU has AFP (alternate floating-point behavior) {A64}.
kASIMD, //!< CPU has ASIMD (NEON on ARM/THUMB).
kBF16, //!< CPU has BF16 (BFloat16 instructions) {A64}.
kBTI, //!< CPU has BTI (branch target identification).
kCPUID, //!< CPU has accessible CPUID register (ID_AA64ZFR0_EL1).
kCRC32, //!< CPU has CRC32 .
kDGH, //!< CPU has DGH (AArch64 only).
kDIT, //!< CPU has data independent timing instructions (DIT).
kDOTPROD, //!< CPU has DOTPROD (SDOT/UDOT).
kCCIDX, //!< CPU has CCIDX (extend of the CCSIDR number of sets).
kCHK, //!< CPU has CHK (CHKFEAT instruction) {A64}.
kCLRBHB, //!< CPU has CLRBHB (clear BHB instruction).
kCPUID, //!< CPU has CPUID (CPUID registers accessible in user-space).
kCRC32, //!< CPU has CRC32 (CRC32 instructions).
kCSSC, //!< CPU has CSSC (common short sequence compression) {A64}.
kD128, //!< CPU has D128 (128-bit translation tables, 56 bit PA) {A64}.
kDGH, //!< CPU has DGH (data gathering hint) {A64}.
kDIT, //!< CPU has DIT (data independent timing of instructions).
kDOTPROD, //!< CPU has DOTPROD (ASIMD Int8 dot product instructions).
kDPB, //!< CPU has DPB (DC CVAP instruction) {A64}.
kDPB2, //!< CPU has DPB2 (DC CVADP instruction) {A64}.
kEBF16, //!< CPU has EBF16 (extended BFloat16 mode) {A64}.
kECV, //!< CPU has ECV (enhanced counter virtualization).
kEDSP, //!< CPU has EDSP (ARM/THUMB only).
kFCMA, //!< CPU has FCMA (FCADD/FCMLA).
kFJCVTZS, //!< CPU has FJCVTZS (AArch64 only).
kFLAGM, //!< CPU has FLAGM (AArch64 only).
kFP16CONV, //!< CPU has FP16 (half-float) conversion.
kFP16FML, //!< CPU has FMLAL{2}/FMLSL{2}
kFP16FULL, //!< CPU has full support for FP16.
kFRINT, //!< CPU has FRINT[32|64][X|Z] (AArch64 only).
kI8MM, //!< CPU has I8MM (AArch64 only).
kIDIVA, //!< CPU has hardware SDIV and UDIV (ARM mode).
kIDIVT, //!< CPU has hardware SDIV and UDIV (THUMB mode).
kLSE, //!< CPU has large system extensions (LSE) (AArch64 only).
kMTE, //!< CPU has MTE (AArch64 only).
kRCPC_IMMO, //!< CPU has RCPC_IMMO (AArch64 only).
kRDM, //!< CPU has RDM (AArch64 only).
kPMU, //!< CPU has PMU (AArch64 only).
kPMULL, //!< CPU has PMULL (AArch64 only).
kRNG, //!< CPU has random number generation (RNG).
kSB, //!< CPU has speculative barrier SB (AArch64 only).
kSHA1, //!< CPU has SHA1.
kSHA2, //!< CPU has SHA2.
kSHA3, //!< CPU has SHA3.
kSHA512, //!< CPU has SHA512.
kSM3, //!< CPU has SM3.
kSM4, //!< CPU has SM4.
kSSBS, //!< CPU has SSBS.
kSVE, //!< CPU has SVE (AArch64 only).
kSVE_BF16, //!< CPU has SVE-BF16 (AArch64 only).
kSVE_F32MM, //!< CPU has SVE-F32MM (AArch64 only).
kSVE_F64MM, //!< CPU has SVE-F64MM (AArch64 only).
kSVE_I8MM, //!< CPU has SVE-I8MM (AArch64 only).
kSVE_PMULL, //!< CPU has SVE-PMULL (AArch64 only).
kSVE2, //!< CPU has SVE2 (AArch64 only).
kSVE2_AES, //!< CPU has SVE2-AES (AArch64 only).
kSVE2_BITPERM, //!< CPU has SVE2-BITPERM (AArch64 only).
kSVE2_SHA3, //!< CPU has SVE2-SHA3 (AArch64 only).
kSVE2_SM4, //!< CPU has SVE2-SM4 (AArch64 only).
kTME, //!< CPU has transactional memory extensions (TME).
kFGT, //!< CPU has FGT (fine-grained traps).
kFGT2, //!< CPU has FGT2 (fine-grained traps 2).
kFHM, //!< CPU has FHM (half-precision floating-point FMLAL instructions).
kFLAGM, //!< CPU has FLAGM (condition flag manipulation) {A64}.
kFLAGM2, //!< CPU has FLAGM2 (condition flag manipulation version v2) {A64}.
kFMAC, //!< CPU has FMAC (ARM/THUMB only).
kFP, //!< CPU has FP (floating-point) (on 32-bit ARM this means VFPv3).
kFP16, //!< CPU has FP16 (half-precision floating-point data processing).
kFP16CONV, //!< CPU has FP16CONV (half-precision float conversion).
kFRINTTS, //!< CPU has FRINTTS (FRINT[32|64][X|Z] instructions) {A64}.
kGCS, //!< CPU has GCS (guarded control stack extension) {A64}.
kHBC, //!< CPU has HBC (hinted conditional branches) {A64}
kHCX, //!< CPU has HCX (support for the HCRX_EL2 register) {A64}.
kI8MM, //!< CPU has I8MM (int8 matrix multiplication) {A64}.
kIDIVA, //!< CPU has IDIV (hardware SDIV and UDIV in ARM mode).
kIDIVT, //!< CPU has IDIV (hardware SDIV and UDIV in THUMB mode).
kJSCVT, //!< CPU has JSCVT (JavaScript FJCVTS conversion instruction) {A64}.
kLOR, //!< CPU has LOR (limited ordering regions extension).
kLRCPC, //!< CPU has LRCPC (load-acquire RCpc instructions) {A64}.
kLRCPC2, //!< CPU has LRCPC2 (load-acquire RCpc instructions v2) {A64}.
kLRCPC3, //!< CPU has LRCPC3 (load-Acquire RCpc instructions v3) {A64}.
kLS64, //!< CPU has LS64 (64 byte loads/stores without return) {A64}.
kLS64_ACCDATA, //!< CPU has LS64_ACCDATA (64-byte EL0 stores with return) {A64}.
kLS64_V, //!< CPU has LS64_V (64-byte stores with return) {A64}.
kLSE, //!< CPU has LSE (large system extensions) {A64}.
kLSE128, //!< CPU has LSE128 (128-bit atomics) {A64}.
kLSE2, //!< CPU has LSE2 (large system extensions v2) {A64}.
kMOPS, //!< CPU has MOPS (memcpy and memset acceleration instructions) {A64}.
kMPAM, //!< CPU has MPAM (memory system partitioning and monitoring extension) {A64}.
kMTE, //!< CPU has MTE (instruction-only memory tagging extension) {A64}.
kMTE2, //!< CPU has MTE2 (full memory tagging extension) {A64}.
kMTE3, //!< CPU has MTE3 (MTE asymmetric fault handling) {A64}.
kMTE4, //!< CPU has MTE4 (MTE v4) {A64}.
kNMI, //!< CPU has NMI (non-maskable Interrupt) {A64}.
kNV, //!< CPU has NV (nested virtualization enchancement) {A64}.
kNV2, //!< CPU has NV2 (enhanced support for nested virtualization) {A64}.
kPAN, //!< CPU has PAN (privileged access-never extension) {A64}.
kPAN2, //!< CPU has PAN2 (PAN s1e1R and s1e1W variants) {A64}.
kPAN3, //!< CPU has PAN3 (support for SCTLR_ELx.EPAN) {A64}.
kPAUTH, //!< CPU has PAUTH (pointer authentication extension) {A64}.
kPMU, //!< CPU has PMU {A64}.
kPMULL, //!< CPU has PMULL {A64}.
kPRFMSLC, //!< CPU has PRFMSLC (PRFM instructions support the SLC target) {A64}
kRAS, //!< CPU has RAS (reliability, availability and serviceability extensions).
kRAS1_1, //!< CPU has RASv1p1 (RAS v1.1).
kRAS2, //!< CPU has RASv2 (RAS v2).
kRDM, //!< CPU has RDM (rounding double multiply accumulate) {A64}.
kRME, //!< CPU has RME (memory encryption contexts extension) {A64}.
kRNG, //!< CPU has RNG (random number generation).
kRNG_TRAP, //!< CPU has RNG_TRAP (random number trap to EL3 field) {A64}.
kRPRES, //!< CPU has RPRES (increased precision of reciprocal estimate and RSQRT estimate) {A64}.
kRPRFM, //!! CPU has RPRFM (range prefetch hint instruction).
kSB, //!< CPU has SB (speculative barrier).
kSHA1, //!< CPU has SHA1 (ASIMD SHA1 instructions).
kSHA256, //!< CPU has SHA256 (ASIMD SHA256 instructions).
kSHA3, //!< CPU has SHA3 (ASIMD EOR3, RAX1, XAR, and BCAX instructions).
kSHA512, //!< CPU has SHA512 (ASIMD SHA512 instructions).
kSM3, //!< CPU has SM3 (ASIMD SM3 instructions).
kSM4, //!< CPU has SM4 (ASIMD SM4 instructions).
kSME, //!< CPU has SME (SME v1 - scalable matrix extension) {A64}.
kSME2, //!< CPU has SME2 (SME v2) {A64}.
kSME2_1, //!< CPU has SME2p1 (SME v2.1) {A64}.
kSME_B16B16, //!< CPU has SME_B16B16 (SME non-widening BFloat16 to BFloat16 arithmetic) {A64}.
kSME_B16F32, //!< CPU has SME_B16F32 {A64}.
kSME_BI32I32, //!< CPU has SME_BI32I32 {A64}.
kSME_F16F16, //!< CPU has SME_F16F16 (SME2.1 non-widening half-precision FP16 to FP16 arithmetic) {A64}.
kSME_F16F32, //!< CPU has SME_F16F32 {A64}.
kSME_F32F32, //!< CPU has SME_F32F32 {A64}.
kSME_F64F64, //!< CPU has SME_F64F64 {A64}.
kSME_FA64, //!< CPU has SME_FA64 {A64}.
kSME_I16I32, //!< CPU has SME_I16I32 {A64}.
kSME_I16I64, //!< CPU has SME_I16I64 {A64}.
kSME_I8I32, //!< CPU has SME_I8I32 {A64}.
kSPECRES, //!< CPU has SPECRES (speculation restriction instructions).
kSPECRES2, //!< CPU has SPECRES2 (clear other speculative predictions).
kSSBS, //!< CPU has SSBS (speculative store bypass safe instruction).
kSSBS2, //!< CPU has SSBS2 (MRS and MSR instructions for SSBS).
kSVE, //!< CPU has SVE (SVE v1 - scalable vector extension) {A64}.
kSVE2, //!< CPU has SVE2 (SVE v2) {A64}.
kSVE2_1, //!< CPU has SVE2p1 (SVE v2.1) {A64}.
kSVE_AES, //!< CPU has SVE_AES (SVE AES instructions) {A64}.
kSVE_B16B16, //!< CPU has SVE_B16B16 (SVE non-widening BFloat16 to BFloat16 arithmetic) {A64}.
kSVE_BF16, //!< CPU has SVE_BF16 (SVE BF16 instructions) {A64}.
kSVE_BITPERM, //!< CPU has SVE_BITPERM (SVE bit permute) {A64}.
kSVE_EBF16, //!< CPU has SVE_EBF16 (SVE extended BFloat16 mode) {A64}.
kSVE_F32MM, //!< CPU has SVE_F32MM (SVE single-precision floating-point matrix multiply instruction) {A64}.
kSVE_F64MM, //!< CPU has SVE_F64MM (SVE double-precision floating-point matrix multiply instruction) {A64}.
kSVE_I8MM, //!< CPU has SVE_I8MM (SVE int8 matrix multiplication) {A64}.
kSVE_PMULL128, //!< CPU has SVE_PMULL128 (SVE PMULL instructions) {A64}.
kSVE_SHA3, //!< CPU has SVE_SHA3 (SVE SHA-3 instructions) {A64}.
kSVE_SM4, //!< CPU has SVE_SM4 (SVE SM4 instructions {A64}.
kSYSINSTR128, //!< CPU has SYSINSTR128 (128-bit system instructions) {A64}.
kSYSREG128, //!< CPU has SYSREG128 (128-bit system registers) {A64}.
kTHE, //!< CPU has THE (translation hardening extension).
kTME, //!< CPU has TME (transactional memory extensions).
kTRF, //!< CPU has TRF (trace extension).
kUAO, //!< CPU has UAO (AArch64 v8.2 UAO PState) {A64}.
kVFP_D32, //!< CPU has VFP_D32 (32 VFP-D registers) (ARM/THUMB only).
kVHE, //!< CPU has VHE (virtual host extension).
kWFXT, //!< CPU has WFxT (WFE and WFI instructions with timeout) {A64}.
kXS, //!< CPU has XS (XS attribute in TLBI and DSB instructions) {A64}.
// @EnumValuesEnd@
kMaxValue = kTME
kMaxValue = kXS
};
#define ASMJIT_ARM_FEATURE(FEATURE) \
@@ -527,67 +624,129 @@ public:
ASMJIT_ARM_FEATURE(ARMv6)
ASMJIT_ARM_FEATURE(ARMv7)
ASMJIT_ARM_FEATURE(ARMv8a)
ASMJIT_ARM_FEATURE(ARMv8_1a)
ASMJIT_ARM_FEATURE(ARMv8_2a)
ASMJIT_ARM_FEATURE(ARMv8_3a)
ASMJIT_ARM_FEATURE(ARMv8_4a)
ASMJIT_ARM_FEATURE(ARMv8_5a)
ASMJIT_ARM_FEATURE(ARMv8_6a)
ASMJIT_ARM_FEATURE(ARMv8_7a)
ASMJIT_ARM_FEATURE(VFPv2)
ASMJIT_ARM_FEATURE(VFPv3)
ASMJIT_ARM_FEATURE(VFPv4)
ASMJIT_ARM_FEATURE(VFP_D32)
ASMJIT_ARM_FEATURE(AES)
ASMJIT_ARM_FEATURE(ALTNZCV)
ASMJIT_ARM_FEATURE(AFP)
ASMJIT_ARM_FEATURE(ASIMD)
ASMJIT_ARM_FEATURE(BF16)
ASMJIT_ARM_FEATURE(BTI)
ASMJIT_ARM_FEATURE(CCIDX)
ASMJIT_ARM_FEATURE(CHK)
ASMJIT_ARM_FEATURE(CLRBHB)
ASMJIT_ARM_FEATURE(CPUID)
ASMJIT_ARM_FEATURE(CRC32)
ASMJIT_ARM_FEATURE(CSSC)
ASMJIT_ARM_FEATURE(D128)
ASMJIT_ARM_FEATURE(DGH)
ASMJIT_ARM_FEATURE(DIT)
ASMJIT_ARM_FEATURE(DOTPROD)
ASMJIT_ARM_FEATURE(DPB)
ASMJIT_ARM_FEATURE(DPB2)
ASMJIT_ARM_FEATURE(EBF16)
ASMJIT_ARM_FEATURE(ECV)
ASMJIT_ARM_FEATURE(EDSP)
ASMJIT_ARM_FEATURE(FCMA)
ASMJIT_ARM_FEATURE(FGT)
ASMJIT_ARM_FEATURE(FGT2)
ASMJIT_ARM_FEATURE(FHM)
ASMJIT_ARM_FEATURE(FLAGM)
ASMJIT_ARM_FEATURE(FLAGM2)
ASMJIT_ARM_FEATURE(FMAC)
ASMJIT_ARM_FEATURE(FP)
ASMJIT_ARM_FEATURE(FP16)
ASMJIT_ARM_FEATURE(FP16CONV)
ASMJIT_ARM_FEATURE(FP16FML)
ASMJIT_ARM_FEATURE(FP16FULL)
ASMJIT_ARM_FEATURE(FRINT)
ASMJIT_ARM_FEATURE(FRINTTS)
ASMJIT_ARM_FEATURE(GCS)
ASMJIT_ARM_FEATURE(HBC)
ASMJIT_ARM_FEATURE(HCX)
ASMJIT_ARM_FEATURE(I8MM)
ASMJIT_ARM_FEATURE(IDIVA)
ASMJIT_ARM_FEATURE(IDIVT)
ASMJIT_ARM_FEATURE(JSCVT)
ASMJIT_ARM_FEATURE(LOR)
ASMJIT_ARM_FEATURE(LRCPC)
ASMJIT_ARM_FEATURE(LRCPC2)
ASMJIT_ARM_FEATURE(LRCPC3)
ASMJIT_ARM_FEATURE(LS64)
ASMJIT_ARM_FEATURE(LS64_ACCDATA)
ASMJIT_ARM_FEATURE(LS64_V)
ASMJIT_ARM_FEATURE(LSE)
ASMJIT_ARM_FEATURE(LSE128)
ASMJIT_ARM_FEATURE(LSE2)
ASMJIT_ARM_FEATURE(MOPS)
ASMJIT_ARM_FEATURE(MPAM)
ASMJIT_ARM_FEATURE(MTE)
ASMJIT_ARM_FEATURE(FJCVTZS)
ASMJIT_ARM_FEATURE(I8MM)
ASMJIT_ARM_FEATURE(RCPC_IMMO)
ASMJIT_ARM_FEATURE(RDM)
ASMJIT_ARM_FEATURE(MTE2)
ASMJIT_ARM_FEATURE(MTE3)
ASMJIT_ARM_FEATURE(MTE4)
ASMJIT_ARM_FEATURE(NMI)
ASMJIT_ARM_FEATURE(NV)
ASMJIT_ARM_FEATURE(NV2)
ASMJIT_ARM_FEATURE(PAN)
ASMJIT_ARM_FEATURE(PAN2)
ASMJIT_ARM_FEATURE(PAN3)
ASMJIT_ARM_FEATURE(PAUTH)
ASMJIT_ARM_FEATURE(PMU)
ASMJIT_ARM_FEATURE(PMULL)
ASMJIT_ARM_FEATURE(PRFMSLC)
ASMJIT_ARM_FEATURE(RAS)
ASMJIT_ARM_FEATURE(RAS1_1)
ASMJIT_ARM_FEATURE(RAS2)
ASMJIT_ARM_FEATURE(RDM)
ASMJIT_ARM_FEATURE(RME)
ASMJIT_ARM_FEATURE(RNG)
ASMJIT_ARM_FEATURE(RNG_TRAP)
ASMJIT_ARM_FEATURE(RPRES)
ASMJIT_ARM_FEATURE(RPRFM)
ASMJIT_ARM_FEATURE(SB)
ASMJIT_ARM_FEATURE(SHA1)
ASMJIT_ARM_FEATURE(SHA2)
ASMJIT_ARM_FEATURE(SHA256)
ASMJIT_ARM_FEATURE(SHA3)
ASMJIT_ARM_FEATURE(SHA512)
ASMJIT_ARM_FEATURE(SM3)
ASMJIT_ARM_FEATURE(SM4)
ASMJIT_ARM_FEATURE(SME)
ASMJIT_ARM_FEATURE(SME2)
ASMJIT_ARM_FEATURE(SME2_1)
ASMJIT_ARM_FEATURE(SME_B16B16)
ASMJIT_ARM_FEATURE(SME_B16F32)
ASMJIT_ARM_FEATURE(SME_BI32I32)
ASMJIT_ARM_FEATURE(SME_F16F16)
ASMJIT_ARM_FEATURE(SME_F16F32)
ASMJIT_ARM_FEATURE(SME_F32F32)
ASMJIT_ARM_FEATURE(SME_F64F64)
ASMJIT_ARM_FEATURE(SME_FA64)
ASMJIT_ARM_FEATURE(SME_I16I32)
ASMJIT_ARM_FEATURE(SME_I16I64)
ASMJIT_ARM_FEATURE(SME_I8I32)
ASMJIT_ARM_FEATURE(SPECRES)
ASMJIT_ARM_FEATURE(SPECRES2)
ASMJIT_ARM_FEATURE(SSBS)
ASMJIT_ARM_FEATURE(SSBS2)
ASMJIT_ARM_FEATURE(SVE)
ASMJIT_ARM_FEATURE(SVE2)
ASMJIT_ARM_FEATURE(SVE2_1)
ASMJIT_ARM_FEATURE(SVE_AES)
ASMJIT_ARM_FEATURE(SVE_B16B16)
ASMJIT_ARM_FEATURE(SVE_BF16)
ASMJIT_ARM_FEATURE(SVE_BITPERM)
ASMJIT_ARM_FEATURE(SVE_EBF16)
ASMJIT_ARM_FEATURE(SVE_F32MM)
ASMJIT_ARM_FEATURE(SVE_F64MM)
ASMJIT_ARM_FEATURE(SVE_I8MM)
ASMJIT_ARM_FEATURE(SVE_PMULL)
ASMJIT_ARM_FEATURE(SVE2)
ASMJIT_ARM_FEATURE(SVE2_AES)
ASMJIT_ARM_FEATURE(SVE2_BITPERM)
ASMJIT_ARM_FEATURE(SVE2_SHA3)
ASMJIT_ARM_FEATURE(SVE2_SM4)
ASMJIT_ARM_FEATURE(SVE_PMULL128)
ASMJIT_ARM_FEATURE(SVE_SHA3)
ASMJIT_ARM_FEATURE(SVE_SM4)
ASMJIT_ARM_FEATURE(SYSINSTR128)
ASMJIT_ARM_FEATURE(SYSREG128)
ASMJIT_ARM_FEATURE(THE)
ASMJIT_ARM_FEATURE(TME)
ASMJIT_ARM_FEATURE(TRF)
ASMJIT_ARM_FEATURE(UAO)
ASMJIT_ARM_FEATURE(VFP_D32)
ASMJIT_ARM_FEATURE(VHE)
ASMJIT_ARM_FEATURE(WFXT)
ASMJIT_ARM_FEATURE(XS)
#undef ASMJIT_ARM_FEATURE
};
@@ -661,6 +820,10 @@ public:
template<typename FeatureId>
inline bool has(const FeatureId& featureId) const noexcept { return _data.has(featureId); }
//! Tests whether any of the features is present.
template<typename... Args>
inline bool hasAny(Args&&... args) const noexcept { return _data.hasAny(std::forward<Args>(args)...); }
//! Tests whether all features as defined by `other` are present.
inline bool hasAll(const CpuFeatures& other) const noexcept { return _data.hasAll(other._data); }
@@ -775,33 +938,47 @@ public:
//! Returns the CPU family ID.
//!
//! Family identifier matches the FamilyId read by using CPUID on X86 architecture.
//! The information provided depends on architecture and OS:
//! - X86:
//! - Family identifier matches the FamilyId read by using CPUID.
//! - ARM:
//! - Apple - returns Apple Family identifier returned by sysctlbyname("hw.cpufamily").
inline uint32_t familyId() const noexcept { return _familyId; }
//! Returns the CPU model ID.
//!
//! Family identifier matches the ModelId read by using CPUID on X86 architecture.
//! The information provided depends on architecture and OS:
//! - X86:
//! - Model identifier matches the ModelId read by using CPUID.
inline uint32_t modelId() const noexcept { return _modelId; }
//! Returns the CPU brand id.
//!
//! Family identifier matches the BrandId read by using CPUID on X86 architecture.
//! The information provided depends on architecture and OS:
//! - X86:
//! - Brand identifier matches the BrandId read by using CPUID.
inline uint32_t brandId() const noexcept { return _brandId; }
//! Returns the CPU stepping.
//!
//! Family identifier matches the Stepping information read by using CPUID on X86 architecture.
//! The information provided depends on architecture and OS:
//! - X86:
//! - Stepping identifier matches the Stepping information read by using CPUID.
inline uint32_t stepping() const noexcept { return _stepping; }
//! Returns the processor type.
//!
//! Family identifier matches the ProcessorType read by using CPUID on X86 architecture.
//! The information provided depends on architecture and OS:
//! - X86:
//! - Processor type identifier matches the ProcessorType read by using CPUID.
inline uint32_t processorType() const noexcept { return _processorType; }
//! Returns the maximum number of logical processors.
inline uint32_t maxLogicalProcessors() const noexcept { return _maxLogicalProcessors; }
//! Returns the size of a cache line flush.
//! Returns the size of a CPU cache line.
//!
//! On a multi-architecture system this should return the smallest cache line of all CPUs.
inline uint32_t cacheLineSize() const noexcept { return _cacheLineSize; }
//! Returns number of hardware threads available.

View File

@@ -107,7 +107,7 @@ Error formatFeature(
return x86::FormatterInternal::formatFeature(sb, featureId);
#endif
#if !defined(ASMJIT_NO_AARCH32) && !defined(ASMJIT_NO_AARCH64)
#if !defined(ASMJIT_NO_AARCH64)
if (Environment::isFamilyARM(arch))
return arm::FormatterInternal::formatFeature(sb, featureId);
#endif

View File

@@ -312,6 +312,17 @@ public:
return id | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
}
static inline constexpr InstId composeARMInstId(uint32_t id, arm::DataType dt, arm::CondCode cc = arm::CondCode::kAL) noexcept {
return id | (uint32_t(dt) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT)>::value)
| (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
}
static inline constexpr InstId composeARMInstId(uint32_t id, arm::DataType dt, arm::DataType dt2, arm::CondCode cc = arm::CondCode::kAL) noexcept {
return id | (uint32_t(dt) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT)>::value)
| (uint32_t(dt2) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT2)>::value)
| (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
}
static inline constexpr InstId extractRealId(uint32_t id) noexcept {
return id & uint32_t(InstIdParts::kRealId);
}

View File

@@ -354,6 +354,9 @@ struct OperandSignature {
inline constexpr OperandSignature subset(uint32_t mask) const noexcept { return OperandSignature{_bits & mask}; }
template<uint32_t kFieldMask, uint32_t kFieldShift = Support::ConstCTZ<kFieldMask>::value>
inline constexpr OperandSignature replacedValue(uint32_t value) const noexcept { return OperandSignature{(_bits & ~kFieldMask) | (value << kFieldShift)}; }
template<uint32_t kFieldMask>
inline constexpr bool matchesSignature(const OperandSignature& signature) const noexcept {
return (_bits & kFieldMask) == signature._bits;

View File

@@ -179,7 +179,7 @@ static constexpr X sar(const X& x, const Y& y) noexcept {
template<typename X, typename Y>
static constexpr X ror(const X& x, const Y& y) noexcept {
typedef typename std::make_unsigned<X>::type U;
return X((U(x) >> y) | (U(x) << (bitSizeOf<U>() - y)));
return X((U(x) >> y) | (U(x) << (bitSizeOf<U>() - U(y))));
}
//! Returns `x | (x >> y)` - helper used by some bit manipulation helpers.

View File

@@ -381,7 +381,7 @@ static int getOSXVersion() noexcept {
if (!ver) {
struct utsname osname {};
uname(&osname);
ver = atoi(osname.release);
ver = strtol(osname.release, nullptr, 10);
globalVersion.store(ver);
}

View File

@@ -954,7 +954,7 @@ CaseX86M_GPB_MulDiv:
break;
case InstDB::kEncodingX86Mr:
opcode.addPrefixBySize(o0.size());
opcode.addPrefixBySize(o1.size());
ASMJIT_FALLTHROUGH;
case InstDB::kEncodingX86Mr_NoSize:
@@ -3010,6 +3010,14 @@ CaseExtRm:
goto CaseVexMri;
case InstDB::kEncodingVexMvr_Wx:
if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
opcode.addWIf(unsigned(Reg::isGpq(o1)));
opReg = x86PackRegAndVvvvv(o1.id(), o2.id());
rmRel = &o0;
goto EmitVexEvexM;
}
case InstDB::kEncodingVexMri_Lx:
opcode |= x86OpcodeLBySize(o0.size() | o1.size());
ASMJIT_FALLTHROUGH;

View File

@@ -471,7 +471,6 @@ public:
ASMJIT_INST_3x(idiv, Idiv, Gp, Gp, Mem) // ANY [EXPLICIT] xDX[Rem]:xAX[Quot] <- xDX:xAX / m16|m32|m64
ASMJIT_INST_2x(imul, Imul, Gp, Gp) // ANY [EXPLICIT] AX <- AL * r8 | ra <- ra * rb
ASMJIT_INST_2x(imul, Imul, Gp, Mem) // ANY [EXPLICIT] AX <- AL * m8 | ra <- ra * m16|m32|m64
ASMJIT_INST_2x(imul, Imul, Gp, Imm) // ANY
ASMJIT_INST_3x(imul, Imul, Gp, Gp, Imm) // ANY
ASMJIT_INST_3x(imul, Imul, Gp, Mem, Imm) // ANY
ASMJIT_INST_3x(imul, Imul, Gp, Gp, Gp) // ANY [EXPLICIT] xDX:xAX <- xAX * r16|r32|r64
@@ -633,6 +632,14 @@ public:
//! \}
//! \name Core Instructions (Aliases)
//! \{
//! The `imul(Gp, Imm)` instruction is an alias of `imul(Gp, Gp, Imm)` instruction.
inline Error imul(const Gp& o0, const Imm& o1) { return _emitter()->_emitI(Inst::kIdImul, o0, o0, o1); }
//! \}
//! \name Deprecated 32-bit Instructions
//! \{
@@ -679,14 +686,6 @@ public:
//! \}
//! \name LAHF/SAHF Instructions
//! \{
ASMJIT_INST_1x(lahf, Lahf, Gp_AH) // LAHFSAHF [EXPLICIT] AH <- EFL
ASMJIT_INST_1x(sahf, Sahf, Gp_AH) // LAHFSAHF [EXPLICIT] EFL <- AH
//! \}
//! \name ADX Instructions
//! \{
@@ -697,13 +696,18 @@ public:
//! \}
//! \name LZCNT/POPCNT Instructions
//! \name CPUID Instruction
//! \{
ASMJIT_INST_2x(lzcnt, Lzcnt, Gp, Gp) // LZCNT
ASMJIT_INST_2x(lzcnt, Lzcnt, Gp, Mem) // LZCNT
ASMJIT_INST_2x(popcnt, Popcnt, Gp, Gp) // POPCNT
ASMJIT_INST_2x(popcnt, Popcnt, Gp, Mem) // POPCNT
ASMJIT_INST_4x(cpuid, Cpuid, Gp_EAX, Gp_EBX, Gp_ECX, Gp_EDX) // I486 [EXPLICIT] EAX:EBX:ECX:EDX <- CPUID[EAX:ECX]
//! \}
//! \name LAHF/SAHF Instructions
//! \{
ASMJIT_INST_1x(lahf, Lahf, Gp_AH) // LAHFSAHF [EXPLICIT] AH <- EFL
ASMJIT_INST_1x(sahf, Sahf, Gp_AH) // LAHFSAHF [EXPLICIT] EFL <- AH
//! \}
@@ -747,27 +751,36 @@ public:
//! \}
//! \name TBM Instructions
//! \name CMPCCXADD Instructions
//! \{
ASMJIT_INST_2x(blcfill, Blcfill, Gp, Gp) // TBM
ASMJIT_INST_2x(blcfill, Blcfill, Gp, Mem) // TBM
ASMJIT_INST_2x(blci, Blci, Gp, Gp) // TBM
ASMJIT_INST_2x(blci, Blci, Gp, Mem) // TBM
ASMJIT_INST_2x(blcic, Blcic, Gp, Gp) // TBM
ASMJIT_INST_2x(blcic, Blcic, Gp, Mem) // TBM
ASMJIT_INST_2x(blcmsk, Blcmsk, Gp, Gp) // TBM
ASMJIT_INST_2x(blcmsk, Blcmsk, Gp, Mem) // TBM
ASMJIT_INST_2x(blcs, Blcs, Gp, Gp) // TBM
ASMJIT_INST_2x(blcs, Blcs, Gp, Mem) // TBM
ASMJIT_INST_2x(blsfill, Blsfill, Gp, Gp) // TBM
ASMJIT_INST_2x(blsfill, Blsfill, Gp, Mem) // TBM
ASMJIT_INST_2x(blsic, Blsic, Gp, Gp) // TBM
ASMJIT_INST_2x(blsic, Blsic, Gp, Mem) // TBM
ASMJIT_INST_2x(t1mskc, T1mskc, Gp, Gp) // TBM
ASMJIT_INST_2x(t1mskc, T1mskc, Gp, Mem) // TBM
ASMJIT_INST_2x(tzmsk, Tzmsk, Gp, Gp) // TBM
ASMJIT_INST_2x(tzmsk, Tzmsk, Gp, Mem) // TBM
ASMJIT_INST_3x(cmpbexadd, Cmpbexadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpbxadd, Cmpbxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmplexadd, Cmplexadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmplxadd, Cmplxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnbexadd, Cmpnbexadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnbxadd, Cmpnbxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnlexadd, Cmpnlexadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnlxadd, Cmpnlxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnoxadd, Cmpnoxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnpxadd, Cmpnpxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnsxadd, Cmpnsxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpnzxadd, Cmpnzxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpoxadd, Cmpoxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmppxadd, Cmppxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpsxadd, Cmpsxadd, Mem, Gp, Gp)
ASMJIT_INST_3x(cmpzxadd, Cmpzxadd, Mem, Gp, Gp)
//! \}
//! \name CacheLine Instructions
//! \{
ASMJIT_INST_1x(cldemote, Cldemote, Mem) // CLDEMOTE
ASMJIT_INST_1x(clflush, Clflush, Mem) // CLFLUSH
ASMJIT_INST_1x(clflushopt, Clflushopt, Mem) // CLFLUSH_OPT
ASMJIT_INST_1x(clwb, Clwb, Mem) // CLWB
ASMJIT_INST_1x(clzero, Clzero, DS_ZAX) // CLZERO [EXPLICIT]
//! \}
@@ -779,6 +792,23 @@ public:
//! \}
//! \name FENCE Instructions (SSE and SSE2)
//! \{
ASMJIT_INST_0x(lfence, Lfence) // SSE2
ASMJIT_INST_0x(mfence, Mfence) // SSE2
ASMJIT_INST_0x(sfence, Sfence) // SSE
//! \}
//! \name LZCNT Instructions
//! \{
ASMJIT_INST_2x(lzcnt, Lzcnt, Gp, Gp) // LZCNT
ASMJIT_INST_2x(lzcnt, Lzcnt, Gp, Mem) // LZCNT
//! \}
//! \name MOVBE Instructions
//! \{
@@ -803,12 +833,11 @@ public:
//! \}
//! \name FENCE Instructions (SSE and SSE2)
//! \name POPCNT Instructions
//! \{
ASMJIT_INST_0x(lfence, Lfence) // SSE2
ASMJIT_INST_0x(mfence, Mfence) // SSE2
ASMJIT_INST_0x(sfence, Sfence) // SSE
ASMJIT_INST_2x(popcnt, Popcnt, Gp, Gp) // POPCNT
ASMJIT_INST_2x(popcnt, Popcnt, Gp, Mem) // POPCNT
//! \}
@@ -825,28 +854,21 @@ public:
//! \}
//! \name CPUID Instruction
//! \name PREFETCHI Instructions
//! \{
ASMJIT_INST_4x(cpuid, Cpuid, Gp_EAX, Gp_EBX, Gp_ECX, Gp_EDX) // I486 [EXPLICIT] EAX:EBX:ECX:EDX <- CPUID[EAX:ECX]
ASMJIT_INST_1x(prefetchit0, Prefetchit0, Mem)
ASMJIT_INST_1x(prefetchit1, Prefetchit1, Mem)
//! \}
//! \name CacheLine Instructions
//! \name RAO_INT Instructions
//! \{
ASMJIT_INST_1x(cldemote, Cldemote, Mem) // CLDEMOTE
ASMJIT_INST_1x(clflush, Clflush, Mem) // CLFLUSH
ASMJIT_INST_1x(clflushopt, Clflushopt, Mem) // CLFLUSH_OPT
ASMJIT_INST_1x(clwb, Clwb, Mem) // CLWB
ASMJIT_INST_1x(clzero, Clzero, DS_ZAX) // CLZERO [EXPLICIT]
//! \}
//! \name SERIALIZE Instruction
//! \{
ASMJIT_INST_0x(serialize, Serialize) // SERIALIZE
ASMJIT_INST_2x(aadd, Aadd, Mem, Gp)
ASMJIT_INST_2x(aand, Aand, Mem, Gp)
ASMJIT_INST_2x(aor, Aor, Mem, Gp)
ASMJIT_INST_2x(axor, Axor, Mem, Gp)
//! \}
@@ -873,6 +895,37 @@ public:
//! \}
//! \name SERIALIZE Instruction
//! \{
ASMJIT_INST_0x(serialize, Serialize) // SERIALIZE
//! \}
//! \name TBM Instructions
//! \{
ASMJIT_INST_2x(blcfill, Blcfill, Gp, Gp) // TBM
ASMJIT_INST_2x(blcfill, Blcfill, Gp, Mem) // TBM
ASMJIT_INST_2x(blci, Blci, Gp, Gp) // TBM
ASMJIT_INST_2x(blci, Blci, Gp, Mem) // TBM
ASMJIT_INST_2x(blcic, Blcic, Gp, Gp) // TBM
ASMJIT_INST_2x(blcic, Blcic, Gp, Mem) // TBM
ASMJIT_INST_2x(blcmsk, Blcmsk, Gp, Gp) // TBM
ASMJIT_INST_2x(blcmsk, Blcmsk, Gp, Mem) // TBM
ASMJIT_INST_2x(blcs, Blcs, Gp, Gp) // TBM
ASMJIT_INST_2x(blcs, Blcs, Gp, Mem) // TBM
ASMJIT_INST_2x(blsfill, Blsfill, Gp, Gp) // TBM
ASMJIT_INST_2x(blsfill, Blsfill, Gp, Mem) // TBM
ASMJIT_INST_2x(blsic, Blsic, Gp, Gp) // TBM
ASMJIT_INST_2x(blsic, Blsic, Gp, Mem) // TBM
ASMJIT_INST_2x(t1mskc, T1mskc, Gp, Gp) // TBM
ASMJIT_INST_2x(t1mskc, T1mskc, Gp, Mem) // TBM
ASMJIT_INST_2x(tzmsk, Tzmsk, Gp, Gp) // TBM
ASMJIT_INST_2x(tzmsk, Tzmsk, Gp, Mem) // TBM
//! \}
//! \name Other User-Mode Instructions
//! \{
@@ -1122,6 +1175,14 @@ public:
//! \}
//! \name INVLPGB Instructions
//! \{
ASMJIT_INST_3x(invlpgb, Invlpgb, Gp_EAX, Gp_EDX, Gp_ECX)
ASMJIT_INST_0x(tlbsync, Tlbsync)
//! \}
//! \name MONITOR Instructions (Privileged)
//! \{
@@ -1172,6 +1233,7 @@ public:
ASMJIT_INST_0x(vmresume, Vmresume) // VMX
ASMJIT_INST_2x(vmwrite, Vmwrite, Gp, Mem) // VMX
ASMJIT_INST_2x(vmwrite, Vmwrite, Gp, Gp) // VMX
ASMJIT_INST_0x(vmxoff, Vmxoff) // VMX
ASMJIT_INST_1x(vmxon, Vmxon, Mem) // VMX
//! \}
@@ -1188,6 +1250,13 @@ public:
//! \}
//! \name SEV_ES Instructions
//! \{
ASMJIT_INST_0x(vmgexit, Vmgexit)
//! \}
//! \name FPU Instructions
//! \{
@@ -3659,6 +3728,83 @@ public:
//! \}
//! \name AVX_NE_CONVERT Instructions
//! \{
ASMJIT_INST_2x(vbcstnebf162ps, Vbcstnebf162ps, Vec, Mem)
ASMJIT_INST_2x(vbcstnesh2ps, Vbcstnesh2ps, Vec, Mem)
ASMJIT_INST_2x(vcvtneebf162ps, Vcvtneebf162ps, Vec, Mem)
ASMJIT_INST_2x(vcvtneeph2ps, Vcvtneeph2ps, Vec, Mem)
ASMJIT_INST_2x(vcvtneobf162ps, Vcvtneobf162ps, Vec, Mem)
ASMJIT_INST_2x(vcvtneoph2ps, Vcvtneoph2ps, Vec, Mem)
//! \}
//! \name AVX_VNNI_INT8 Instructions
//! \{
ASMJIT_INST_3x(vpdpbssd, Vpdpbssd, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbssd, Vpdpbssd, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpbssds, Vpdpbssds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbssds, Vpdpbssds, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpbsud, Vpdpbsud, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbsud, Vpdpbsud, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpbsuds, Vpdpbsuds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbsuds, Vpdpbsuds, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpbuud, Vpdpbuud, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbuud, Vpdpbuud, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpbuuds, Vpdpbuuds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpbuuds, Vpdpbuuds, Vec, Vec, Mem)
//! \}
//! \name AVX_VNNI_INT16 Instructions
//! \{
ASMJIT_INST_3x(vpdpwsud, Vpdpwsud, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwsud, Vpdpwsud, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpwsuds, Vpdpwsuds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwsuds, Vpdpwsuds, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpwusd, Vpdpwusd, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwusd, Vpdpwusd, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpwusds, Vpdpwusds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwusds, Vpdpwusds, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpwuud, Vpdpwuud, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwuud, Vpdpwuud, Vec, Vec, Mem)
ASMJIT_INST_3x(vpdpwuuds, Vpdpwuuds, Vec, Vec, Vec)
ASMJIT_INST_3x(vpdpwuuds, Vpdpwuuds, Vec, Vec, Mem)
//! \}
//! \name AVX+SHA512 Instructions
//! \{
ASMJIT_INST_2x(vsha512msg1, Vsha512msg1, Vec, Vec)
ASMJIT_INST_2x(vsha512msg2, Vsha512msg2, Vec, Vec)
ASMJIT_INST_3x(vsha512rnds2, Vsha512rnds2, Vec, Vec, Vec)
//! \}
//! \name AVX+SM3 Instructions
//! \{
ASMJIT_INST_3x(vsm3msg1, Vsm3msg1, Vec, Vec, Vec)
ASMJIT_INST_3x(vsm3msg1, Vsm3msg1, Vec, Vec, Mem)
ASMJIT_INST_3x(vsm3msg2, Vsm3msg2, Vec, Vec, Vec)
ASMJIT_INST_3x(vsm3msg2, Vsm3msg2, Vec, Vec, Mem)
ASMJIT_INST_4x(vsm3rnds2, Vsm3rnds2, Vec, Vec, Vec, Imm)
ASMJIT_INST_4x(vsm3rnds2, Vsm3rnds2, Vec, Vec, Mem, Imm)
//! \}
//! \name AVX+SM4 Instructions
//! \{
ASMJIT_INST_3x(vsm4key4, Vsm4key4, Vec, Vec, Vec)
ASMJIT_INST_3x(vsm4key4, Vsm4key4, Vec, Vec, Mem)
ASMJIT_INST_3x(vsm4rnds4, Vsm4rnds4, Vec, Vec, Vec)
ASMJIT_INST_3x(vsm4rnds4, Vsm4rnds4, Vec, Vec, Mem)
//! \}
//! \name AVX512_FP16 Instructions
//! \{
@@ -3880,22 +4026,48 @@ public:
//! \}
//! \name AMX Instructions
//! \name AMX_TILE Instructions
//! \{
ASMJIT_INST_1x(ldtilecfg, Ldtilecfg, Mem) // AMX_TILE
ASMJIT_INST_1x(sttilecfg, Sttilecfg, Mem) // AMX_TILE
ASMJIT_INST_2x(tileloadd, Tileloadd, Tmm, Mem) // AMX_TILE
ASMJIT_INST_2x(tileloaddt1, Tileloaddt1, Tmm, Mem) // AMX_TILE
ASMJIT_INST_0x(tilerelease, Tilerelease) // AMX_TILE
ASMJIT_INST_2x(tilestored, Tilestored, Mem, Tmm) // AMX_TILE
ASMJIT_INST_1x(tilezero, Tilezero, Tmm) // AMX_TILE
ASMJIT_INST_1x(ldtilecfg, Ldtilecfg, Mem)
ASMJIT_INST_1x(sttilecfg, Sttilecfg, Mem)
ASMJIT_INST_2x(tileloadd, Tileloadd, Tmm, Mem)
ASMJIT_INST_2x(tileloaddt1, Tileloaddt1, Tmm, Mem)
ASMJIT_INST_0x(tilerelease, Tilerelease)
ASMJIT_INST_2x(tilestored, Tilestored, Mem, Tmm)
ASMJIT_INST_1x(tilezero, Tilezero, Tmm)
ASMJIT_INST_3x(tdpbf16ps, Tdpbf16ps, Tmm, Tmm, Tmm) // AMX_BF16
ASMJIT_INST_3x(tdpbssd, Tdpbssd, Tmm, Tmm, Tmm) // AMX_INT8
ASMJIT_INST_3x(tdpbsud, Tdpbsud, Tmm, Tmm, Tmm) // AMX_INT8
ASMJIT_INST_3x(tdpbusd, Tdpbusd, Tmm, Tmm, Tmm) // AMX_INT8
ASMJIT_INST_3x(tdpbuud, Tdpbuud, Tmm, Tmm, Tmm) // AMX_INT8
//! \}
//! \name AMX_BF16 Instructions
//! \{
ASMJIT_INST_3x(tdpbf16ps, Tdpbf16ps, Tmm, Tmm, Tmm)
//! \}
//! \name AMX_COMPLEX Instructions
//! \{
ASMJIT_INST_3x(tcmmimfp16ps, Tcmmimfp16ps, Tmm, Tmm, Tmm)
ASMJIT_INST_3x(tcmmrlfp16ps, Tcmmrlfp16ps, Tmm, Tmm, Tmm)
//! \}
//! \name AMX_FP16 Instructions
//! \{
ASMJIT_INST_3x(tdpfp16ps, Tdpfp16ps, Tmm, Tmm, Tmm)
//! \}
//! \name AMX_INT8 Instructions
//! \{
ASMJIT_INST_3x(tdpbssd, Tdpbssd, Tmm, Tmm, Tmm)
ASMJIT_INST_3x(tdpbsud, Tdpbsud, Tmm, Tmm, Tmm)
ASMJIT_INST_3x(tdpbusd, Tdpbusd, Tmm, Tmm, Tmm)
ASMJIT_INST_3x(tdpbuud, Tdpbuud, Tmm, Tmm, Tmm)
//! \}
};
@@ -4167,6 +4339,16 @@ struct EmitterImplicitT : public EmitterExplicitT<This> {
//! \}
//! \name SEAM Instructions
//! \{
ASMJIT_INST_0x(seamcall, Seamcall)
ASMJIT_INST_0x(seamops, Seamops)
ASMJIT_INST_0x(seamret, Seamret)
ASMJIT_INST_0x(tdcall, Tdcall)
//! \}
//! \name Privileged Instructions
//! \{

View File

@@ -198,9 +198,11 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"AESNI\0"
"ALTMOVCR8\0"
"AMX_BF16\0"
"AMX_COMPLEX\0"
"AMX_FP16\0"
"AMX_INT8\0"
"AMX_TILE\0"
"APX_F\0"
"AVX\0"
"AVX2\0"
"AVX512_4FMAPS\0"
@@ -208,13 +210,13 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"AVX512_BF16\0"
"AVX512_BITALG\0"
"AVX512_BW\0"
"AVX512_CDI\0"
"AVX512_CD\0"
"AVX512_DQ\0"
"AVX512_ERI\0"
"AVX512_ER\0"
"AVX512_F\0"
"AVX512_FP16\0"
"AVX512_IFMA\0"
"AVX512_PFI\0"
"AVX512_PF\0"
"AVX512_VBMI\0"
"AVX512_VBMI2\0"
"AVX512_VL\0"
@@ -224,6 +226,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"AVX_IFMA\0"
"AVX_NE_CONVERT\0"
"AVX_VNNI\0"
"AVX_VNNI_INT16\0"
"AVX_VNNI_INT8\0"
"BMI\0"
"BMI2\0"
@@ -258,6 +261,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"HLE\0"
"HRESET\0"
"I486\0"
"INVLPGB\0"
"LAHFSAHF\0"
"LAM\0"
"LWP\0"
@@ -284,6 +288,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"PREFETCHWT1\0"
"PTWRITE\0"
"RAO_INT\0"
"RMPQUERY\0"
"RDPID\0"
"RDPRU\0"
"RDRAND\0"
@@ -291,13 +296,20 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"RDTSC\0"
"RDTSCP\0"
"RTM\0"
"SEAM\0"
"SERIALIZE\0"
"SEV\0"
"SEV_ES\0"
"SEV_SNP\0"
"SHA\0"
"SHA512\0"
"SKINIT\0"
"SM3\0"
"SM4\0"
"SMAP\0"
"SME\0"
"SMEP\0"
"SMX\0"
"SNP\0"
"SSE\0"
"SSE2\0"
"SSE3\0"
@@ -307,6 +319,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"SSSE3\0"
"SVM\0"
"TBM\0"
"TSE\0"
"TSX\0"
"TSXLDTRK\0"
"UINTR\0"
@@ -324,15 +337,16 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"<Unknown>\0";
static const uint16_t sFeatureIndex[] = {
0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 62, 71, 80, 84, 89, 103, 117, 129, 143,
153, 164, 174, 185, 194, 206, 218, 229, 241, 254, 264, 276, 296, 313, 322,
337, 346, 360, 364, 369, 377, 384, 392, 401, 409, 420, 425, 432, 437, 447,
458, 468, 474, 481, 486, 491, 495, 500, 504, 513, 518, 523, 528, 533, 541,
546, 552, 557, 561, 568, 573, 582, 586, 590, 596, 604, 608, 613, 621, 630,
636, 646, 654, 658, 662, 670, 675, 683, 689, 699, 707, 714, 724, 734, 746,
754, 762, 768, 774, 781, 788, 794, 801, 805, 815, 819, 826, 831, 836, 840,
844, 848, 853, 858, 865, 872, 878, 884, 888, 892, 896, 905, 911, 916, 920,
931, 939, 948, 956, 960, 966, 973, 982, 989
0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 65, 74, 83, 92, 98, 102, 107, 121, 135,
147, 161, 171, 181, 191, 201, 210, 222, 234, 244, 256, 269, 279, 291, 311,
328, 337, 352, 361, 376, 390, 394, 399, 407, 414, 422, 431, 439, 450, 455,
462, 467, 477, 488, 498, 504, 511, 516, 521, 525, 530, 534, 543, 548, 553,
558, 563, 571, 576, 582, 587, 591, 598, 603, 611, 620, 624, 628, 634, 642,
646, 651, 659, 668, 674, 684, 692, 696, 700, 708, 713, 721, 727, 737, 745,
752, 762, 772, 784, 792, 800, 809, 815, 821, 828, 835, 841, 848, 852, 857,
867, 871, 878, 886, 890, 897, 904, 908, 912, 917, 921, 926, 930, 934, 939,
944, 951, 958, 964, 970, 974, 978, 982, 986, 995, 1001, 1006, 1010, 1021,
1029, 1038, 1046, 1050, 1056, 1063, 1072, 1079
};
// @EnumStringEnd@

View File

@@ -119,7 +119,9 @@ namespace Inst {
kIdNone = 0, //!< Invalid instruction id.
kIdAaa, //!< Instruction 'aaa' (X86).
kIdAad, //!< Instruction 'aad' (X86).
kIdAadd, //!< Instruction 'aadd' {RAO_INT}.
kIdAam, //!< Instruction 'aam' (X86).
kIdAand, //!< Instruction 'aand' {RAO_INT}.
kIdAas, //!< Instruction 'aas' (X86).
kIdAdc, //!< Instruction 'adc'.
kIdAdcx, //!< Instruction 'adcx' {ADX}.
@@ -143,7 +145,9 @@ namespace Inst {
kIdAndnps, //!< Instruction 'andnps' {SSE}.
kIdAndpd, //!< Instruction 'andpd' {SSE2}.
kIdAndps, //!< Instruction 'andps' {SSE}.
kIdAor, //!< Instruction 'aor' {RAO_INT}.
kIdArpl, //!< Instruction 'arpl' (X86).
kIdAxor, //!< Instruction 'axor' {RAO_INT}.
kIdBextr, //!< Instruction 'bextr' {BMI}.
kIdBlcfill, //!< Instruction 'blcfill' {TBM}.
kIdBlci, //!< Instruction 'blci' {TBM}.
@@ -224,14 +228,30 @@ namespace Inst {
kIdCmovs, //!< Instruction 'cmovs' {CMOV}.
kIdCmovz, //!< Instruction 'cmovz' {CMOV}.
kIdCmp, //!< Instruction 'cmp'.
kIdCmpbexadd, //!< Instruction 'cmpbexadd' {CMPCCXADD}.
kIdCmpbxadd, //!< Instruction 'cmpbxadd' {CMPCCXADD}.
kIdCmplexadd, //!< Instruction 'cmplexadd' {CMPCCXADD}.
kIdCmplxadd, //!< Instruction 'cmplxadd' {CMPCCXADD}.
kIdCmpnbexadd, //!< Instruction 'cmpnbexadd' {CMPCCXADD}.
kIdCmpnbxadd, //!< Instruction 'cmpnbxadd' {CMPCCXADD}.
kIdCmpnlexadd, //!< Instruction 'cmpnlexadd' {CMPCCXADD}.
kIdCmpnlxadd, //!< Instruction 'cmpnlxadd' {CMPCCXADD}.
kIdCmpnoxadd, //!< Instruction 'cmpnoxadd' {CMPCCXADD}.
kIdCmpnpxadd, //!< Instruction 'cmpnpxadd' {CMPCCXADD}.
kIdCmpnsxadd, //!< Instruction 'cmpnsxadd' {CMPCCXADD}.
kIdCmpnzxadd, //!< Instruction 'cmpnzxadd' {CMPCCXADD}.
kIdCmpoxadd, //!< Instruction 'cmpoxadd' {CMPCCXADD}.
kIdCmppd, //!< Instruction 'cmppd' {SSE2}.
kIdCmpps, //!< Instruction 'cmpps' {SSE}.
kIdCmppxadd, //!< Instruction 'cmppxadd' {CMPCCXADD}.
kIdCmps, //!< Instruction 'cmps'.
kIdCmpsd, //!< Instruction 'cmpsd' {SSE2}.
kIdCmpss, //!< Instruction 'cmpss' {SSE}.
kIdCmpsxadd, //!< Instruction 'cmpsxadd' {CMPCCXADD}.
kIdCmpxchg, //!< Instruction 'cmpxchg' {I486}.
kIdCmpxchg16b, //!< Instruction 'cmpxchg16b' {CMPXCHG16B} (X64).
kIdCmpxchg8b, //!< Instruction 'cmpxchg8b' {CMPXCHG8B}.
kIdCmpzxadd, //!< Instruction 'cmpzxadd' {CMPCCXADD}.
kIdComisd, //!< Instruction 'comisd' {SSE2}.
kIdComiss, //!< Instruction 'comiss' {SSE}.
kIdCpuid, //!< Instruction 'cpuid' {I486}.
@@ -279,104 +299,104 @@ namespace Inst {
kIdEnter, //!< Instruction 'enter'.
kIdExtractps, //!< Instruction 'extractps' {SSE4_1}.
kIdExtrq, //!< Instruction 'extrq' {SSE4A}.
kIdF2xm1, //!< Instruction 'f2xm1'.
kIdFabs, //!< Instruction 'fabs'.
kIdFadd, //!< Instruction 'fadd'.
kIdFaddp, //!< Instruction 'faddp'.
kIdFbld, //!< Instruction 'fbld'.
kIdFbstp, //!< Instruction 'fbstp'.
kIdFchs, //!< Instruction 'fchs'.
kIdFclex, //!< Instruction 'fclex'.
kIdFcmovb, //!< Instruction 'fcmovb' {CMOV}.
kIdFcmovbe, //!< Instruction 'fcmovbe' {CMOV}.
kIdFcmove, //!< Instruction 'fcmove' {CMOV}.
kIdFcmovnb, //!< Instruction 'fcmovnb' {CMOV}.
kIdFcmovnbe, //!< Instruction 'fcmovnbe' {CMOV}.
kIdFcmovne, //!< Instruction 'fcmovne' {CMOV}.
kIdFcmovnu, //!< Instruction 'fcmovnu' {CMOV}.
kIdFcmovu, //!< Instruction 'fcmovu' {CMOV}.
kIdFcom, //!< Instruction 'fcom'.
kIdFcomi, //!< Instruction 'fcomi'.
kIdFcomip, //!< Instruction 'fcomip'.
kIdFcomp, //!< Instruction 'fcomp'.
kIdFcompp, //!< Instruction 'fcompp'.
kIdFcos, //!< Instruction 'fcos'.
kIdFdecstp, //!< Instruction 'fdecstp'.
kIdFdiv, //!< Instruction 'fdiv'.
kIdFdivp, //!< Instruction 'fdivp'.
kIdFdivr, //!< Instruction 'fdivr'.
kIdFdivrp, //!< Instruction 'fdivrp'.
kIdF2xm1, //!< Instruction 'f2xm1' {FPU}.
kIdFabs, //!< Instruction 'fabs' {FPU}.
kIdFadd, //!< Instruction 'fadd' {FPU}.
kIdFaddp, //!< Instruction 'faddp' {FPU}.
kIdFbld, //!< Instruction 'fbld' {FPU}.
kIdFbstp, //!< Instruction 'fbstp' {FPU}.
kIdFchs, //!< Instruction 'fchs' {FPU}.
kIdFclex, //!< Instruction 'fclex' {FPU}.
kIdFcmovb, //!< Instruction 'fcmovb' {CMOV|FPU}.
kIdFcmovbe, //!< Instruction 'fcmovbe' {CMOV|FPU}.
kIdFcmove, //!< Instruction 'fcmove' {CMOV|FPU}.
kIdFcmovnb, //!< Instruction 'fcmovnb' {CMOV|FPU}.
kIdFcmovnbe, //!< Instruction 'fcmovnbe' {CMOV|FPU}.
kIdFcmovne, //!< Instruction 'fcmovne' {CMOV|FPU}.
kIdFcmovnu, //!< Instruction 'fcmovnu' {CMOV|FPU}.
kIdFcmovu, //!< Instruction 'fcmovu' {CMOV|FPU}.
kIdFcom, //!< Instruction 'fcom' {FPU}.
kIdFcomi, //!< Instruction 'fcomi' {FPU}.
kIdFcomip, //!< Instruction 'fcomip' {FPU}.
kIdFcomp, //!< Instruction 'fcomp' {FPU}.
kIdFcompp, //!< Instruction 'fcompp' {FPU}.
kIdFcos, //!< Instruction 'fcos' {FPU}.
kIdFdecstp, //!< Instruction 'fdecstp' {FPU}.
kIdFdiv, //!< Instruction 'fdiv' {FPU}.
kIdFdivp, //!< Instruction 'fdivp' {FPU}.
kIdFdivr, //!< Instruction 'fdivr' {FPU}.
kIdFdivrp, //!< Instruction 'fdivrp' {FPU}.
kIdFemms, //!< Instruction 'femms' {3DNOW}.
kIdFfree, //!< Instruction 'ffree'.
kIdFiadd, //!< Instruction 'fiadd'.
kIdFicom, //!< Instruction 'ficom'.
kIdFicomp, //!< Instruction 'ficomp'.
kIdFidiv, //!< Instruction 'fidiv'.
kIdFidivr, //!< Instruction 'fidivr'.
kIdFild, //!< Instruction 'fild'.
kIdFimul, //!< Instruction 'fimul'.
kIdFincstp, //!< Instruction 'fincstp'.
kIdFinit, //!< Instruction 'finit'.
kIdFist, //!< Instruction 'fist'.
kIdFistp, //!< Instruction 'fistp'.
kIdFisttp, //!< Instruction 'fisttp' {SSE3}.
kIdFisub, //!< Instruction 'fisub'.
kIdFisubr, //!< Instruction 'fisubr'.
kIdFld, //!< Instruction 'fld'.
kIdFld1, //!< Instruction 'fld1'.
kIdFldcw, //!< Instruction 'fldcw'.
kIdFldenv, //!< Instruction 'fldenv'.
kIdFldl2e, //!< Instruction 'fldl2e'.
kIdFldl2t, //!< Instruction 'fldl2t'.
kIdFldlg2, //!< Instruction 'fldlg2'.
kIdFldln2, //!< Instruction 'fldln2'.
kIdFldpi, //!< Instruction 'fldpi'.
kIdFldz, //!< Instruction 'fldz'.
kIdFmul, //!< Instruction 'fmul'.
kIdFmulp, //!< Instruction 'fmulp'.
kIdFnclex, //!< Instruction 'fnclex'.
kIdFninit, //!< Instruction 'fninit'.
kIdFnop, //!< Instruction 'fnop'.
kIdFnsave, //!< Instruction 'fnsave'.
kIdFnstcw, //!< Instruction 'fnstcw'.
kIdFnstenv, //!< Instruction 'fnstenv'.
kIdFnstsw, //!< Instruction 'fnstsw'.
kIdFpatan, //!< Instruction 'fpatan'.
kIdFprem, //!< Instruction 'fprem'.
kIdFprem1, //!< Instruction 'fprem1'.
kIdFptan, //!< Instruction 'fptan'.
kIdFrndint, //!< Instruction 'frndint'.
kIdFrstor, //!< Instruction 'frstor'.
kIdFsave, //!< Instruction 'fsave'.
kIdFscale, //!< Instruction 'fscale'.
kIdFsin, //!< Instruction 'fsin'.
kIdFsincos, //!< Instruction 'fsincos'.
kIdFsqrt, //!< Instruction 'fsqrt'.
kIdFst, //!< Instruction 'fst'.
kIdFstcw, //!< Instruction 'fstcw'.
kIdFstenv, //!< Instruction 'fstenv'.
kIdFstp, //!< Instruction 'fstp'.
kIdFstsw, //!< Instruction 'fstsw'.
kIdFsub, //!< Instruction 'fsub'.
kIdFsubp, //!< Instruction 'fsubp'.
kIdFsubr, //!< Instruction 'fsubr'.
kIdFsubrp, //!< Instruction 'fsubrp'.
kIdFtst, //!< Instruction 'ftst'.
kIdFucom, //!< Instruction 'fucom'.
kIdFucomi, //!< Instruction 'fucomi'.
kIdFucomip, //!< Instruction 'fucomip'.
kIdFucomp, //!< Instruction 'fucomp'.
kIdFucompp, //!< Instruction 'fucompp'.
kIdFwait, //!< Instruction 'fwait'.
kIdFxam, //!< Instruction 'fxam'.
kIdFxch, //!< Instruction 'fxch'.
kIdFfree, //!< Instruction 'ffree' {FPU}.
kIdFiadd, //!< Instruction 'fiadd' {FPU}.
kIdFicom, //!< Instruction 'ficom' {FPU}.
kIdFicomp, //!< Instruction 'ficomp' {FPU}.
kIdFidiv, //!< Instruction 'fidiv' {FPU}.
kIdFidivr, //!< Instruction 'fidivr' {FPU}.
kIdFild, //!< Instruction 'fild' {FPU}.
kIdFimul, //!< Instruction 'fimul' {FPU}.
kIdFincstp, //!< Instruction 'fincstp' {FPU}.
kIdFinit, //!< Instruction 'finit' {FPU}.
kIdFist, //!< Instruction 'fist' {FPU}.
kIdFistp, //!< Instruction 'fistp' {FPU}.
kIdFisttp, //!< Instruction 'fisttp' {SSE3|FPU}.
kIdFisub, //!< Instruction 'fisub' {FPU}.
kIdFisubr, //!< Instruction 'fisubr' {FPU}.
kIdFld, //!< Instruction 'fld' {FPU}.
kIdFld1, //!< Instruction 'fld1' {FPU}.
kIdFldcw, //!< Instruction 'fldcw' {FPU}.
kIdFldenv, //!< Instruction 'fldenv' {FPU}.
kIdFldl2e, //!< Instruction 'fldl2e' {FPU}.
kIdFldl2t, //!< Instruction 'fldl2t' {FPU}.
kIdFldlg2, //!< Instruction 'fldlg2' {FPU}.
kIdFldln2, //!< Instruction 'fldln2' {FPU}.
kIdFldpi, //!< Instruction 'fldpi' {FPU}.
kIdFldz, //!< Instruction 'fldz' {FPU}.
kIdFmul, //!< Instruction 'fmul' {FPU}.
kIdFmulp, //!< Instruction 'fmulp' {FPU}.
kIdFnclex, //!< Instruction 'fnclex' {FPU}.
kIdFninit, //!< Instruction 'fninit' {FPU}.
kIdFnop, //!< Instruction 'fnop' {FPU}.
kIdFnsave, //!< Instruction 'fnsave' {FPU}.
kIdFnstcw, //!< Instruction 'fnstcw' {FPU}.
kIdFnstenv, //!< Instruction 'fnstenv' {FPU}.
kIdFnstsw, //!< Instruction 'fnstsw' {FPU}.
kIdFpatan, //!< Instruction 'fpatan' {FPU}.
kIdFprem, //!< Instruction 'fprem' {FPU}.
kIdFprem1, //!< Instruction 'fprem1' {FPU}.
kIdFptan, //!< Instruction 'fptan' {FPU}.
kIdFrndint, //!< Instruction 'frndint' {FPU}.
kIdFrstor, //!< Instruction 'frstor' {FPU}.
kIdFsave, //!< Instruction 'fsave' {FPU}.
kIdFscale, //!< Instruction 'fscale' {FPU}.
kIdFsin, //!< Instruction 'fsin' {FPU}.
kIdFsincos, //!< Instruction 'fsincos' {FPU}.
kIdFsqrt, //!< Instruction 'fsqrt' {FPU}.
kIdFst, //!< Instruction 'fst' {FPU}.
kIdFstcw, //!< Instruction 'fstcw' {FPU}.
kIdFstenv, //!< Instruction 'fstenv' {FPU}.
kIdFstp, //!< Instruction 'fstp' {FPU}.
kIdFstsw, //!< Instruction 'fstsw' {FPU}.
kIdFsub, //!< Instruction 'fsub' {FPU}.
kIdFsubp, //!< Instruction 'fsubp' {FPU}.
kIdFsubr, //!< Instruction 'fsubr' {FPU}.
kIdFsubrp, //!< Instruction 'fsubrp' {FPU}.
kIdFtst, //!< Instruction 'ftst' {FPU}.
kIdFucom, //!< Instruction 'fucom' {FPU}.
kIdFucomi, //!< Instruction 'fucomi' {FPU}.
kIdFucomip, //!< Instruction 'fucomip' {FPU}.
kIdFucomp, //!< Instruction 'fucomp' {FPU}.
kIdFucompp, //!< Instruction 'fucompp' {FPU}.
kIdFwait, //!< Instruction 'fwait' {FPU}.
kIdFxam, //!< Instruction 'fxam' {FPU}.
kIdFxch, //!< Instruction 'fxch' {FPU}.
kIdFxrstor, //!< Instruction 'fxrstor' {FXSR}.
kIdFxrstor64, //!< Instruction 'fxrstor64' {FXSR} (X64).
kIdFxsave, //!< Instruction 'fxsave' {FXSR}.
kIdFxsave64, //!< Instruction 'fxsave64' {FXSR} (X64).
kIdFxtract, //!< Instruction 'fxtract'.
kIdFyl2x, //!< Instruction 'fyl2x'.
kIdFyl2xp1, //!< Instruction 'fyl2xp1'.
kIdFxtract, //!< Instruction 'fxtract' {FPU}.
kIdFyl2x, //!< Instruction 'fyl2x' {FPU}.
kIdFyl2xp1, //!< Instruction 'fyl2xp1' {FPU}.
kIdGetsec, //!< Instruction 'getsec' {SMX}.
kIdGf2p8affineinvqb, //!< Instruction 'gf2p8affineinvqb' {GFNI}.
kIdGf2p8affineqb, //!< Instruction 'gf2p8affineqb' {GFNI}.
@@ -403,6 +423,7 @@ namespace Inst {
kIdInvept, //!< Instruction 'invept' {VMX}.
kIdInvlpg, //!< Instruction 'invlpg' {I486}.
kIdInvlpga, //!< Instruction 'invlpga' {SVM}.
kIdInvlpgb, //!< Instruction 'invlpgb' {INVLPGB}.
kIdInvpcid, //!< Instruction 'invpcid' {I486}.
kIdInvvpid, //!< Instruction 'invvpid' {VMX}.
kIdIret, //!< Instruction 'iret'.
@@ -535,7 +556,7 @@ namespace Inst {
kIdMonitor, //!< Instruction 'monitor' {MONITOR}.
kIdMonitorx, //!< Instruction 'monitorx' {MONITORX}.
kIdMov, //!< Instruction 'mov'.
kIdMovabs, //!< Instruction 'movabs' (X64).
kIdMovabs, //!< Instruction 'movabs'.
kIdMovapd, //!< Instruction 'movapd' {SSE2}.
kIdMovaps, //!< Instruction 'movaps' {SSE}.
kIdMovbe, //!< Instruction 'movbe' {MOVBE}.
@@ -606,7 +627,7 @@ namespace Inst {
kIdPaddusb, //!< Instruction 'paddusb' {MMX|SSE2}.
kIdPaddusw, //!< Instruction 'paddusw' {MMX|SSE2}.
kIdPaddw, //!< Instruction 'paddw' {MMX|SSE2}.
kIdPalignr, //!< Instruction 'palignr' {SSE3}.
kIdPalignr, //!< Instruction 'palignr' {SSSE3}.
kIdPand, //!< Instruction 'pand' {MMX|SSE2}.
kIdPandn, //!< Instruction 'pandn' {MMX|SSE2}.
kIdPause, //!< Instruction 'pause'.
@@ -713,10 +734,12 @@ namespace Inst {
kIdPopfq, //!< Instruction 'popfq' (X64).
kIdPor, //!< Instruction 'por' {MMX|SSE2}.
kIdPrefetch, //!< Instruction 'prefetch' {3DNOW}.
kIdPrefetchnta, //!< Instruction 'prefetchnta' {MMX2}.
kIdPrefetcht0, //!< Instruction 'prefetcht0' {MMX2}.
kIdPrefetcht1, //!< Instruction 'prefetcht1' {MMX2}.
kIdPrefetcht2, //!< Instruction 'prefetcht2' {MMX2}.
kIdPrefetchit0, //!< Instruction 'prefetchit0' {PREFETCHI} (X64).
kIdPrefetchit1, //!< Instruction 'prefetchit1' {PREFETCHI} (X64).
kIdPrefetchnta, //!< Instruction 'prefetchnta' {SSE}.
kIdPrefetcht0, //!< Instruction 'prefetcht0' {SSE}.
kIdPrefetcht1, //!< Instruction 'prefetcht1' {SSE}.
kIdPrefetcht2, //!< Instruction 'prefetcht2' {SSE}.
kIdPrefetchw, //!< Instruction 'prefetchw' {PREFETCHW}.
kIdPrefetchwt1, //!< Instruction 'prefetchwt1' {PREFETCHWT1}.
kIdPsadbw, //!< Instruction 'psadbw' {MMX2|SSE2}.
@@ -732,7 +755,7 @@ namespace Inst {
kIdPslldq, //!< Instruction 'pslldq' {SSE2}.
kIdPsllq, //!< Instruction 'psllq' {MMX|SSE2}.
kIdPsllw, //!< Instruction 'psllw' {MMX|SSE2}.
kIdPsmash, //!< Instruction 'psmash' {SNP} (X64).
kIdPsmash, //!< Instruction 'psmash' {SEV_SNP} (X64).
kIdPsrad, //!< Instruction 'psrad' {MMX|SSE2}.
kIdPsraw, //!< Instruction 'psraw' {MMX|SSE2}.
kIdPsrld, //!< Instruction 'psrld' {MMX|SSE2}.
@@ -764,7 +787,7 @@ namespace Inst {
kIdPushf, //!< Instruction 'pushf'.
kIdPushfd, //!< Instruction 'pushfd' (X86).
kIdPushfq, //!< Instruction 'pushfq' (X64).
kIdPvalidate, //!< Instruction 'pvalidate' {SNP}.
kIdPvalidate, //!< Instruction 'pvalidate' {SEV_SNP}.
kIdPxor, //!< Instruction 'pxor' {MMX|SSE2}.
kIdRcl, //!< Instruction 'rcl'.
kIdRcpps, //!< Instruction 'rcpps' {SSE}.
@@ -785,8 +808,8 @@ namespace Inst {
kIdRdtscp, //!< Instruction 'rdtscp' {RDTSCP}.
kIdRet, //!< Instruction 'ret'.
kIdRetf, //!< Instruction 'retf'.
kIdRmpadjust, //!< Instruction 'rmpadjust' {SNP} (X64).
kIdRmpupdate, //!< Instruction 'rmpupdate' {SNP} (X64).
kIdRmpadjust, //!< Instruction 'rmpadjust' {SEV_SNP} (X64).
kIdRmpupdate, //!< Instruction 'rmpupdate' {SEV_SNP} (X64).
kIdRol, //!< Instruction 'rol'.
kIdRor, //!< Instruction 'ror'.
kIdRorx, //!< Instruction 'rorx' {BMI2}.
@@ -805,6 +828,9 @@ namespace Inst {
kIdSaveprevssp, //!< Instruction 'saveprevssp' {CET_SS}.
kIdSbb, //!< Instruction 'sbb'.
kIdScas, //!< Instruction 'scas'.
kIdSeamcall, //!< Instruction 'seamcall' {SEAM}.
kIdSeamops, //!< Instruction 'seamops' {SEAM}.
kIdSeamret, //!< Instruction 'seamret' {SEAM}.
kIdSenduipi, //!< Instruction 'senduipi' {UINTR} (X64).
kIdSerialize, //!< Instruction 'serialize' {SERIALIZE}.
kIdSeta, //!< Instruction 'seta'.
@@ -838,7 +864,7 @@ namespace Inst {
kIdSets, //!< Instruction 'sets'.
kIdSetssbsy, //!< Instruction 'setssbsy' {CET_SS}.
kIdSetz, //!< Instruction 'setz'.
kIdSfence, //!< Instruction 'sfence' {MMX2}.
kIdSfence, //!< Instruction 'sfence' {SSE}.
kIdSgdt, //!< Instruction 'sgdt'.
kIdSha1msg1, //!< Instruction 'sha1msg1' {SHA}.
kIdSha1msg2, //!< Instruction 'sha1msg2' {SHA}.
@@ -883,15 +909,19 @@ namespace Inst {
kIdSyscall, //!< Instruction 'syscall' (X64).
kIdSysenter, //!< Instruction 'sysenter'.
kIdSysexit, //!< Instruction 'sysexit'.
kIdSysexitq, //!< Instruction 'sysexitq'.
kIdSysexitq, //!< Instruction 'sysexitq' (X64).
kIdSysret, //!< Instruction 'sysret' (X64).
kIdSysretq, //!< Instruction 'sysretq' (X64).
kIdT1mskc, //!< Instruction 't1mskc' {TBM}.
kIdTcmmimfp16ps, //!< Instruction 'tcmmimfp16ps' {AMX_COMPLEX} (X64).
kIdTcmmrlfp16ps, //!< Instruction 'tcmmrlfp16ps' {AMX_COMPLEX} (X64).
kIdTdcall, //!< Instruction 'tdcall' {SEAM}.
kIdTdpbf16ps, //!< Instruction 'tdpbf16ps' {AMX_BF16} (X64).
kIdTdpbssd, //!< Instruction 'tdpbssd' {AMX_INT8} (X64).
kIdTdpbsud, //!< Instruction 'tdpbsud' {AMX_INT8} (X64).
kIdTdpbusd, //!< Instruction 'tdpbusd' {AMX_INT8} (X64).
kIdTdpbuud, //!< Instruction 'tdpbuud' {AMX_INT8} (X64).
kIdTdpfp16ps, //!< Instruction 'tdpfp16ps' {AMX_FP16} (X64).
kIdTest, //!< Instruction 'test'.
kIdTestui, //!< Instruction 'testui' {UINTR} (X64).
kIdTileloadd, //!< Instruction 'tileloadd' {AMX_TILE} (X64).
@@ -899,6 +929,7 @@ namespace Inst {
kIdTilerelease, //!< Instruction 'tilerelease' {AMX_TILE} (X64).
kIdTilestored, //!< Instruction 'tilestored' {AMX_TILE} (X64).
kIdTilezero, //!< Instruction 'tilezero' {AMX_TILE} (X64).
kIdTlbsync, //!< Instruction 'tlbsync' {INVLPGB}.
kIdTpause, //!< Instruction 'tpause' {WAITPKG}.
kIdTzcnt, //!< Instruction 'tzcnt' {BMI}.
kIdTzmsk, //!< Instruction 'tzmsk' {TBM}.
@@ -938,6 +969,8 @@ namespace Inst {
kIdVandnps, //!< Instruction 'vandnps' {AVX|AVX512_DQ+VL}.
kIdVandpd, //!< Instruction 'vandpd' {AVX|AVX512_DQ+VL}.
kIdVandps, //!< Instruction 'vandps' {AVX|AVX512_DQ+VL}.
kIdVbcstnebf162ps, //!< Instruction 'vbcstnebf162ps' {AVX_NE_CONVERT}.
kIdVbcstnesh2ps, //!< Instruction 'vbcstnesh2ps' {AVX_NE_CONVERT}.
kIdVblendmpd, //!< Instruction 'vblendmpd' {AVX512_F+VL}.
kIdVblendmps, //!< Instruction 'vblendmps' {AVX512_F+VL}.
kIdVblendpd, //!< Instruction 'vblendpd' {AVX}.
@@ -973,7 +1006,11 @@ namespace Inst {
kIdVcvtdq2ph, //!< Instruction 'vcvtdq2ph' {AVX512_FP16+VL}.
kIdVcvtdq2ps, //!< Instruction 'vcvtdq2ps' {AVX|AVX512_F+VL}.
kIdVcvtne2ps2bf16, //!< Instruction 'vcvtne2ps2bf16' {AVX512_BF16+VL}.
kIdVcvtneps2bf16, //!< Instruction 'vcvtneps2bf16' {AVX512_BF16+VL}.
kIdVcvtneebf162ps, //!< Instruction 'vcvtneebf162ps' {AVX_NE_CONVERT}.
kIdVcvtneeph2ps, //!< Instruction 'vcvtneeph2ps' {AVX_NE_CONVERT}.
kIdVcvtneobf162ps, //!< Instruction 'vcvtneobf162ps' {AVX_NE_CONVERT}.
kIdVcvtneoph2ps, //!< Instruction 'vcvtneoph2ps' {AVX_NE_CONVERT}.
kIdVcvtneps2bf16, //!< Instruction 'vcvtneps2bf16' {AVX_NE_CONVERT|AVX512_BF16+VL}.
kIdVcvtpd2dq, //!< Instruction 'vcvtpd2dq' {AVX|AVX512_F+VL}.
kIdVcvtpd2ph, //!< Instruction 'vcvtpd2ph' {AVX512_FP16+VL}.
kIdVcvtpd2ps, //!< Instruction 'vcvtpd2ps' {AVX|AVX512_F+VL}.
@@ -1057,8 +1094,8 @@ namespace Inst {
kIdVdpps, //!< Instruction 'vdpps' {AVX}.
kIdVerr, //!< Instruction 'verr'.
kIdVerw, //!< Instruction 'verw'.
kIdVexp2pd, //!< Instruction 'vexp2pd' {AVX512_ERI}.
kIdVexp2ps, //!< Instruction 'vexp2ps' {AVX512_ERI}.
kIdVexp2pd, //!< Instruction 'vexp2pd' {AVX512_ER}.
kIdVexp2ps, //!< Instruction 'vexp2ps' {AVX512_ER}.
kIdVexpandpd, //!< Instruction 'vexpandpd' {AVX512_F+VL}.
kIdVexpandps, //!< Instruction 'vexpandps' {AVX512_F+VL}.
kIdVextractf128, //!< Instruction 'vextractf128' {AVX}.
@@ -1073,9 +1110,9 @@ namespace Inst {
kIdVextracti64x4, //!< Instruction 'vextracti64x4' {AVX512_F}.
kIdVextractps, //!< Instruction 'vextractps' {AVX|AVX512_F}.
kIdVfcmaddcph, //!< Instruction 'vfcmaddcph' {AVX512_FP16+VL}.
kIdVfcmaddcsh, //!< Instruction 'vfcmaddcsh' {AVX512_FP16+VL}.
kIdVfcmaddcsh, //!< Instruction 'vfcmaddcsh' {AVX512_FP16}.
kIdVfcmulcph, //!< Instruction 'vfcmulcph' {AVX512_FP16+VL}.
kIdVfcmulcsh, //!< Instruction 'vfcmulcsh' {AVX512_FP16+VL}.
kIdVfcmulcsh, //!< Instruction 'vfcmulcsh' {AVX512_FP16}.
kIdVfixupimmpd, //!< Instruction 'vfixupimmpd' {AVX512_F+VL}.
kIdVfixupimmps, //!< Instruction 'vfixupimmps' {AVX512_F+VL}.
kIdVfixupimmsd, //!< Instruction 'vfixupimmsd' {AVX512_F}.
@@ -1099,7 +1136,7 @@ namespace Inst {
kIdVfmadd231sh, //!< Instruction 'vfmadd231sh' {AVX512_FP16}.
kIdVfmadd231ss, //!< Instruction 'vfmadd231ss' {FMA|AVX512_F}.
kIdVfmaddcph, //!< Instruction 'vfmaddcph' {AVX512_FP16+VL}.
kIdVfmaddcsh, //!< Instruction 'vfmaddcsh' {AVX512_FP16+VL}.
kIdVfmaddcsh, //!< Instruction 'vfmaddcsh' {AVX512_FP16}.
kIdVfmaddpd, //!< Instruction 'vfmaddpd' {FMA4}.
kIdVfmaddps, //!< Instruction 'vfmaddps' {FMA4}.
kIdVfmaddsd, //!< Instruction 'vfmaddsd' {FMA4}.
@@ -1206,14 +1243,14 @@ namespace Inst {
kIdVfrczss, //!< Instruction 'vfrczss' {XOP}.
kIdVgatherdpd, //!< Instruction 'vgatherdpd' {AVX2|AVX512_F+VL}.
kIdVgatherdps, //!< Instruction 'vgatherdps' {AVX2|AVX512_F+VL}.
kIdVgatherpf0dpd, //!< Instruction 'vgatherpf0dpd' {AVX512_PFI}.
kIdVgatherpf0dps, //!< Instruction 'vgatherpf0dps' {AVX512_PFI}.
kIdVgatherpf0qpd, //!< Instruction 'vgatherpf0qpd' {AVX512_PFI}.
kIdVgatherpf0qps, //!< Instruction 'vgatherpf0qps' {AVX512_PFI}.
kIdVgatherpf1dpd, //!< Instruction 'vgatherpf1dpd' {AVX512_PFI}.
kIdVgatherpf1dps, //!< Instruction 'vgatherpf1dps' {AVX512_PFI}.
kIdVgatherpf1qpd, //!< Instruction 'vgatherpf1qpd' {AVX512_PFI}.
kIdVgatherpf1qps, //!< Instruction 'vgatherpf1qps' {AVX512_PFI}.
kIdVgatherpf0dpd, //!< Instruction 'vgatherpf0dpd' {AVX512_PF}.
kIdVgatherpf0dps, //!< Instruction 'vgatherpf0dps' {AVX512_PF}.
kIdVgatherpf0qpd, //!< Instruction 'vgatherpf0qpd' {AVX512_PF}.
kIdVgatherpf0qps, //!< Instruction 'vgatherpf0qps' {AVX512_PF}.
kIdVgatherpf1dpd, //!< Instruction 'vgatherpf1dpd' {AVX512_PF}.
kIdVgatherpf1dps, //!< Instruction 'vgatherpf1dps' {AVX512_PF}.
kIdVgatherpf1qpd, //!< Instruction 'vgatherpf1qpd' {AVX512_PF}.
kIdVgatherpf1qps, //!< Instruction 'vgatherpf1qps' {AVX512_PF}.
kIdVgatherqpd, //!< Instruction 'vgatherqpd' {AVX2|AVX512_F+VL}.
kIdVgatherqps, //!< Instruction 'vgatherqps' {AVX2|AVX512_F+VL}.
kIdVgetexppd, //!< Instruction 'vgetexppd' {AVX512_F+VL}.
@@ -1254,18 +1291,19 @@ namespace Inst {
kIdVmaxpd, //!< Instruction 'vmaxpd' {AVX|AVX512_F+VL}.
kIdVmaxph, //!< Instruction 'vmaxph' {AVX512_FP16+VL}.
kIdVmaxps, //!< Instruction 'vmaxps' {AVX|AVX512_F+VL}.
kIdVmaxsd, //!< Instruction 'vmaxsd' {AVX|AVX512_F+VL}.
kIdVmaxsd, //!< Instruction 'vmaxsd' {AVX|AVX512_F}.
kIdVmaxsh, //!< Instruction 'vmaxsh' {AVX512_FP16}.
kIdVmaxss, //!< Instruction 'vmaxss' {AVX|AVX512_F+VL}.
kIdVmaxss, //!< Instruction 'vmaxss' {AVX|AVX512_F}.
kIdVmcall, //!< Instruction 'vmcall' {VMX}.
kIdVmclear, //!< Instruction 'vmclear' {VMX}.
kIdVmfunc, //!< Instruction 'vmfunc' {VMX}.
kIdVmgexit, //!< Instruction 'vmgexit' {SEV_ES}.
kIdVminpd, //!< Instruction 'vminpd' {AVX|AVX512_F+VL}.
kIdVminph, //!< Instruction 'vminph' {AVX512_FP16+VL}.
kIdVminps, //!< Instruction 'vminps' {AVX|AVX512_F+VL}.
kIdVminsd, //!< Instruction 'vminsd' {AVX|AVX512_F+VL}.
kIdVminsd, //!< Instruction 'vminsd' {AVX|AVX512_F}.
kIdVminsh, //!< Instruction 'vminsh' {AVX512_FP16}.
kIdVminss, //!< Instruction 'vminss' {AVX|AVX512_F+VL}.
kIdVminss, //!< Instruction 'vminss' {AVX|AVX512_F}.
kIdVmlaunch, //!< Instruction 'vmlaunch' {VMX}.
kIdVmload, //!< Instruction 'vmload' {SVM}.
kIdVmmcall, //!< Instruction 'vmmcall' {SVM}.
@@ -1316,11 +1354,12 @@ namespace Inst {
kIdVmulsh, //!< Instruction 'vmulsh' {AVX512_FP16}.
kIdVmulss, //!< Instruction 'vmulss' {AVX|AVX512_F}.
kIdVmwrite, //!< Instruction 'vmwrite' {VMX}.
kIdVmxoff, //!< Instruction 'vmxoff' {VMX}.
kIdVmxon, //!< Instruction 'vmxon' {VMX}.
kIdVorpd, //!< Instruction 'vorpd' {AVX|AVX512_DQ+VL}.
kIdVorps, //!< Instruction 'vorps' {AVX|AVX512_DQ+VL}.
kIdVp2intersectd, //!< Instruction 'vp2intersectd' {AVX512_VP2INTERSECT}.
kIdVp2intersectq, //!< Instruction 'vp2intersectq' {AVX512_VP2INTERSECT}.
kIdVp2intersectd, //!< Instruction 'vp2intersectd' {AVX512_VP2INTERSECT+VL}.
kIdVp2intersectq, //!< Instruction 'vp2intersectq' {AVX512_VP2INTERSECT+VL}.
kIdVp4dpwssd, //!< Instruction 'vp4dpwssd' {AVX512_4VNNIW}.
kIdVp4dpwssds, //!< Instruction 'vp4dpwssds' {AVX512_4VNNIW}.
kIdVpabsb, //!< Instruction 'vpabsb' {AVX|AVX2|AVX512_BW+VL}.
@@ -1357,8 +1396,8 @@ namespace Inst {
kIdVpblendw, //!< Instruction 'vpblendw' {AVX|AVX2}.
kIdVpbroadcastb, //!< Instruction 'vpbroadcastb' {AVX2|AVX512_BW+VL}.
kIdVpbroadcastd, //!< Instruction 'vpbroadcastd' {AVX2|AVX512_F+VL}.
kIdVpbroadcastmb2q, //!< Instruction 'vpbroadcastmb2q' {AVX512_CDI+VL}.
kIdVpbroadcastmw2d, //!< Instruction 'vpbroadcastmw2d' {AVX512_CDI+VL}.
kIdVpbroadcastmb2q, //!< Instruction 'vpbroadcastmb2q' {AVX512_CD+VL}.
kIdVpbroadcastmw2d, //!< Instruction 'vpbroadcastmw2d' {AVX512_CD+VL}.
kIdVpbroadcastq, //!< Instruction 'vpbroadcastq' {AVX2|AVX512_F+VL}.
kIdVpbroadcastw, //!< Instruction 'vpbroadcastw' {AVX2|AVX512_BW+VL}.
kIdVpclmulqdq, //!< Instruction 'vpclmulqdq' {AVX|AVX512_F+VL & PCLMULQDQ|VPCLMULQDQ}.
@@ -1395,12 +1434,24 @@ namespace Inst {
kIdVpcomuq, //!< Instruction 'vpcomuq' {XOP}.
kIdVpcomuw, //!< Instruction 'vpcomuw' {XOP}.
kIdVpcomw, //!< Instruction 'vpcomw' {XOP}.
kIdVpconflictd, //!< Instruction 'vpconflictd' {AVX512_CDI+VL}.
kIdVpconflictq, //!< Instruction 'vpconflictq' {AVX512_CDI+VL}.
kIdVpconflictd, //!< Instruction 'vpconflictd' {AVX512_CD+VL}.
kIdVpconflictq, //!< Instruction 'vpconflictq' {AVX512_CD+VL}.
kIdVpdpbssd, //!< Instruction 'vpdpbssd' {AVX_VNNI_INT8}.
kIdVpdpbssds, //!< Instruction 'vpdpbssds' {AVX_VNNI_INT8}.
kIdVpdpbsud, //!< Instruction 'vpdpbsud' {AVX_VNNI_INT8}.
kIdVpdpbsuds, //!< Instruction 'vpdpbsuds' {AVX_VNNI_INT8}.
kIdVpdpbusd, //!< Instruction 'vpdpbusd' {AVX_VNNI|AVX512_VNNI+VL}.
kIdVpdpbusds, //!< Instruction 'vpdpbusds' {AVX_VNNI|AVX512_VNNI+VL}.
kIdVpdpbuud, //!< Instruction 'vpdpbuud' {AVX_VNNI_INT8}.
kIdVpdpbuuds, //!< Instruction 'vpdpbuuds' {AVX_VNNI_INT8}.
kIdVpdpwssd, //!< Instruction 'vpdpwssd' {AVX_VNNI|AVX512_VNNI+VL}.
kIdVpdpwssds, //!< Instruction 'vpdpwssds' {AVX_VNNI|AVX512_VNNI+VL}.
kIdVpdpwsud, //!< Instruction 'vpdpwsud' {AVX_VNNI_INT16}.
kIdVpdpwsuds, //!< Instruction 'vpdpwsuds' {AVX_VNNI_INT16}.
kIdVpdpwusd, //!< Instruction 'vpdpwusd' {AVX_VNNI_INT16}.
kIdVpdpwusds, //!< Instruction 'vpdpwusds' {AVX_VNNI_INT16}.
kIdVpdpwuud, //!< Instruction 'vpdpwuud' {AVX_VNNI_INT16}.
kIdVpdpwuuds, //!< Instruction 'vpdpwuuds' {AVX_VNNI_INT16}.
kIdVperm2f128, //!< Instruction 'vperm2f128' {AVX}.
kIdVperm2i128, //!< Instruction 'vperm2i128' {AVX2}.
kIdVpermb, //!< Instruction 'vpermb' {AVX512_VBMI+VL}.
@@ -1463,8 +1514,8 @@ namespace Inst {
kIdVpinsrd, //!< Instruction 'vpinsrd' {AVX|AVX512_DQ}.
kIdVpinsrq, //!< Instruction 'vpinsrq' {AVX|AVX512_DQ} (X64).
kIdVpinsrw, //!< Instruction 'vpinsrw' {AVX|AVX512_BW}.
kIdVplzcntd, //!< Instruction 'vplzcntd' {AVX512_CDI+VL}.
kIdVplzcntq, //!< Instruction 'vplzcntq' {AVX512_CDI+VL}.
kIdVplzcntd, //!< Instruction 'vplzcntd' {AVX512_CD+VL}.
kIdVplzcntq, //!< Instruction 'vplzcntq' {AVX512_CD+VL}.
kIdVpmacsdd, //!< Instruction 'vpmacsdd' {XOP}.
kIdVpmacsdqh, //!< Instruction 'vpmacsdqh' {XOP}.
kIdVpmacsdql, //!< Instruction 'vpmacsdql' {XOP}.
@@ -1477,8 +1528,8 @@ namespace Inst {
kIdVpmacsww, //!< Instruction 'vpmacsww' {XOP}.
kIdVpmadcsswd, //!< Instruction 'vpmadcsswd' {XOP}.
kIdVpmadcswd, //!< Instruction 'vpmadcswd' {XOP}.
kIdVpmadd52huq, //!< Instruction 'vpmadd52huq' {AVX512_IFMA+VL}.
kIdVpmadd52luq, //!< Instruction 'vpmadd52luq' {AVX512_IFMA+VL}.
kIdVpmadd52huq, //!< Instruction 'vpmadd52huq' {AVX_IFMA|AVX512_IFMA+VL}.
kIdVpmadd52luq, //!< Instruction 'vpmadd52luq' {AVX_IFMA|AVX512_IFMA+VL}.
kIdVpmaddubsw, //!< Instruction 'vpmaddubsw' {AVX|AVX2|AVX512_BW+VL}.
kIdVpmaddwd, //!< Instruction 'vpmaddwd' {AVX|AVX2|AVX512_BW+VL}.
kIdVpmaskmovd, //!< Instruction 'vpmaskmovd' {AVX2}.
@@ -1658,10 +1709,10 @@ namespace Inst {
kIdVrcp14ps, //!< Instruction 'vrcp14ps' {AVX512_F+VL}.
kIdVrcp14sd, //!< Instruction 'vrcp14sd' {AVX512_F}.
kIdVrcp14ss, //!< Instruction 'vrcp14ss' {AVX512_F}.
kIdVrcp28pd, //!< Instruction 'vrcp28pd' {AVX512_ERI}.
kIdVrcp28ps, //!< Instruction 'vrcp28ps' {AVX512_ERI}.
kIdVrcp28sd, //!< Instruction 'vrcp28sd' {AVX512_ERI}.
kIdVrcp28ss, //!< Instruction 'vrcp28ss' {AVX512_ERI}.
kIdVrcp28pd, //!< Instruction 'vrcp28pd' {AVX512_ER}.
kIdVrcp28ps, //!< Instruction 'vrcp28ps' {AVX512_ER}.
kIdVrcp28sd, //!< Instruction 'vrcp28sd' {AVX512_ER}.
kIdVrcp28ss, //!< Instruction 'vrcp28ss' {AVX512_ER}.
kIdVrcpph, //!< Instruction 'vrcpph' {AVX512_FP16}.
kIdVrcpps, //!< Instruction 'vrcpps' {AVX}.
kIdVrcpsh, //!< Instruction 'vrcpsh' {AVX512_FP16}.
@@ -1686,10 +1737,10 @@ namespace Inst {
kIdVrsqrt14ps, //!< Instruction 'vrsqrt14ps' {AVX512_F+VL}.
kIdVrsqrt14sd, //!< Instruction 'vrsqrt14sd' {AVX512_F}.
kIdVrsqrt14ss, //!< Instruction 'vrsqrt14ss' {AVX512_F}.
kIdVrsqrt28pd, //!< Instruction 'vrsqrt28pd' {AVX512_ERI}.
kIdVrsqrt28ps, //!< Instruction 'vrsqrt28ps' {AVX512_ERI}.
kIdVrsqrt28sd, //!< Instruction 'vrsqrt28sd' {AVX512_ERI}.
kIdVrsqrt28ss, //!< Instruction 'vrsqrt28ss' {AVX512_ERI}.
kIdVrsqrt28pd, //!< Instruction 'vrsqrt28pd' {AVX512_ER}.
kIdVrsqrt28ps, //!< Instruction 'vrsqrt28ps' {AVX512_ER}.
kIdVrsqrt28sd, //!< Instruction 'vrsqrt28sd' {AVX512_ER}.
kIdVrsqrt28ss, //!< Instruction 'vrsqrt28ss' {AVX512_ER}.
kIdVrsqrtph, //!< Instruction 'vrsqrtph' {AVX512_FP16+VL}.
kIdVrsqrtps, //!< Instruction 'vrsqrtps' {AVX}.
kIdVrsqrtsh, //!< Instruction 'vrsqrtsh' {AVX512_FP16}.
@@ -1702,22 +1753,30 @@ namespace Inst {
kIdVscalefss, //!< Instruction 'vscalefss' {AVX512_F}.
kIdVscatterdpd, //!< Instruction 'vscatterdpd' {AVX512_F+VL}.
kIdVscatterdps, //!< Instruction 'vscatterdps' {AVX512_F+VL}.
kIdVscatterpf0dpd, //!< Instruction 'vscatterpf0dpd' {AVX512_PFI}.
kIdVscatterpf0dps, //!< Instruction 'vscatterpf0dps' {AVX512_PFI}.
kIdVscatterpf0qpd, //!< Instruction 'vscatterpf0qpd' {AVX512_PFI}.
kIdVscatterpf0qps, //!< Instruction 'vscatterpf0qps' {AVX512_PFI}.
kIdVscatterpf1dpd, //!< Instruction 'vscatterpf1dpd' {AVX512_PFI}.
kIdVscatterpf1dps, //!< Instruction 'vscatterpf1dps' {AVX512_PFI}.
kIdVscatterpf1qpd, //!< Instruction 'vscatterpf1qpd' {AVX512_PFI}.
kIdVscatterpf1qps, //!< Instruction 'vscatterpf1qps' {AVX512_PFI}.
kIdVscatterpf0dpd, //!< Instruction 'vscatterpf0dpd' {AVX512_PF}.
kIdVscatterpf0dps, //!< Instruction 'vscatterpf0dps' {AVX512_PF}.
kIdVscatterpf0qpd, //!< Instruction 'vscatterpf0qpd' {AVX512_PF}.
kIdVscatterpf0qps, //!< Instruction 'vscatterpf0qps' {AVX512_PF}.
kIdVscatterpf1dpd, //!< Instruction 'vscatterpf1dpd' {AVX512_PF}.
kIdVscatterpf1dps, //!< Instruction 'vscatterpf1dps' {AVX512_PF}.
kIdVscatterpf1qpd, //!< Instruction 'vscatterpf1qpd' {AVX512_PF}.
kIdVscatterpf1qps, //!< Instruction 'vscatterpf1qps' {AVX512_PF}.
kIdVscatterqpd, //!< Instruction 'vscatterqpd' {AVX512_F+VL}.
kIdVscatterqps, //!< Instruction 'vscatterqps' {AVX512_F+VL}.
kIdVsha512msg1, //!< Instruction 'vsha512msg1' {AVX & SHA512}.
kIdVsha512msg2, //!< Instruction 'vsha512msg2' {AVX & SHA512}.
kIdVsha512rnds2, //!< Instruction 'vsha512rnds2' {AVX & SHA512}.
kIdVshuff32x4, //!< Instruction 'vshuff32x4' {AVX512_F+VL}.
kIdVshuff64x2, //!< Instruction 'vshuff64x2' {AVX512_F+VL}.
kIdVshufi32x4, //!< Instruction 'vshufi32x4' {AVX512_F+VL}.
kIdVshufi64x2, //!< Instruction 'vshufi64x2' {AVX512_F+VL}.
kIdVshufpd, //!< Instruction 'vshufpd' {AVX|AVX512_F+VL}.
kIdVshufps, //!< Instruction 'vshufps' {AVX|AVX512_F+VL}.
kIdVsm3msg1, //!< Instruction 'vsm3msg1' {AVX & SM3}.
kIdVsm3msg2, //!< Instruction 'vsm3msg2' {AVX & SM3}.
kIdVsm3rnds2, //!< Instruction 'vsm3rnds2' {AVX & SM3}.
kIdVsm4key4, //!< Instruction 'vsm4key4' {AVX & SM4}.
kIdVsm4rnds4, //!< Instruction 'vsm4rnds4' {AVX & SM4}.
kIdVsqrtpd, //!< Instruction 'vsqrtpd' {AVX|AVX512_F+VL}.
kIdVsqrtph, //!< Instruction 'vsqrtph' {AVX512_FP16+VL}.
kIdVsqrtps, //!< Instruction 'vsqrtps' {AVX|AVX512_F+VL}.
@@ -1744,7 +1803,7 @@ namespace Inst {
kIdVxorps, //!< Instruction 'vxorps' {AVX|AVX512_DQ+VL}.
kIdVzeroall, //!< Instruction 'vzeroall' {AVX}.
kIdVzeroupper, //!< Instruction 'vzeroupper' {AVX}.
kIdWbinvd, //!< Instruction 'wbinvd'.
kIdWbinvd, //!< Instruction 'wbinvd' {I486}.
kIdWbnoinvd, //!< Instruction 'wbnoinvd' {WBNOINVD}.
kIdWrfsbase, //!< Instruction 'wrfsbase' {FSGSBASE} (X64).
kIdWrgsbase, //!< Instruction 'wrgsbase' {FSGSBASE} (X64).

View File

@@ -1501,6 +1501,8 @@ static inline uint32_t InstInternal_usesAvx512(InstOptions instOptions, const Re
}
Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
typedef CpuFeatures::X86 Ext;
// Only called when `arch` matches X86 family.
DebugUtils::unused(arch);
ASMJIT_ASSERT(Environment::isFamilyX86(arch));
@@ -1533,19 +1535,19 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
RegAnalysis regAnalysis = InstInternal_regAnalysis(operands, opCount);
// Handle MMX vs SSE overlap.
if (out->has(CpuFeatures::X86::kMMX) || out->has(CpuFeatures::X86::kMMX2)) {
if (out->has(Ext::kMMX) || out->has(Ext::kMMX2)) {
// Only instructions defined by SSE and SSE2 overlap. Instructions introduced by newer instruction sets like
// SSE3+ don't state MMX as they require SSE3+.
if (out->has(CpuFeatures::X86::kSSE) || out->has(CpuFeatures::X86::kSSE2)) {
if (out->has(Ext::kSSE) || out->has(Ext::kSSE2)) {
if (!regAnalysis.hasRegType(RegType::kX86_Xmm)) {
// The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only.
out->remove(CpuFeatures::X86::kSSE);
out->remove(CpuFeatures::X86::kSSE2);
out->remove(CpuFeatures::X86::kSSE4_1);
out->remove(Ext::kSSE);
out->remove(Ext::kSSE2);
out->remove(Ext::kSSE4_1);
}
else {
out->remove(CpuFeatures::X86::kMMX);
out->remove(CpuFeatures::X86::kMMX2);
out->remove(Ext::kMMX);
out->remove(Ext::kMMX2);
}
// Special case: PEXTRW instruction is MMX/SSE2 instruction. However, MMX/SSE version cannot access memory
@@ -1554,30 +1556,30 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
// is, of course, not compatible with MMX/SSE2 and would #UD if SSE4.1 is not supported.
if (instId == Inst::kIdPextrw) {
if (opCount >= 1 && operands[0].isMem())
out->remove(CpuFeatures::X86::kSSE2);
out->remove(Ext::kSSE2);
else
out->remove(CpuFeatures::X86::kSSE4_1);
out->remove(Ext::kSSE4_1);
}
}
}
// Handle PCLMULQDQ vs VPCLMULQDQ.
if (out->has(CpuFeatures::X86::kVPCLMULQDQ)) {
if (out->has(Ext::kVPCLMULQDQ)) {
if (regAnalysis.hasRegType(RegType::kX86_Zmm) || Support::test(options, InstOptions::kX86_Evex)) {
// AVX512_F & VPCLMULQDQ.
out->remove(CpuFeatures::X86::kAVX, CpuFeatures::X86::kPCLMULQDQ);
out->remove(Ext::kAVX, Ext::kPCLMULQDQ);
}
else if (regAnalysis.hasRegType(RegType::kX86_Ymm)) {
out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_VL);
out->remove(Ext::kAVX512_F, Ext::kAVX512_VL);
}
else {
// AVX & PCLMULQDQ.
out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_VL, CpuFeatures::X86::kVPCLMULQDQ);
out->remove(Ext::kAVX512_F, Ext::kAVX512_VL, Ext::kVPCLMULQDQ);
}
}
// Handle AVX vs AVX2 overlap.
if (out->has(CpuFeatures::X86::kAVX) && out->has(CpuFeatures::X86::kAVX2)) {
if (out->has(Ext::kAVX) && out->has(Ext::kAVX2)) {
bool isAVX2 = true;
// Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but only version that uses memory as a
// source operand. AVX2 then added support for register source operand.
@@ -1594,31 +1596,44 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
}
if (isAVX2)
out->remove(CpuFeatures::X86::kAVX);
out->remove(Ext::kAVX);
else
out->remove(CpuFeatures::X86::kAVX2);
out->remove(Ext::kAVX2);
}
// Handle AVX|AVX2|FMA|F16C vs AVX512 overlap.
if (out->has(CpuFeatures::X86::kAVX) || out->has(CpuFeatures::X86::kAVX2) || out->has(CpuFeatures::X86::kFMA) || out->has(CpuFeatures::X86::kF16C)) {
// Only AVX512-F|BW|DQ allow to encode AVX/AVX2/FMA/F16C instructions
if (out->has(CpuFeatures::X86::kAVX512_F) || out->has(CpuFeatures::X86::kAVX512_BW) || out->has(CpuFeatures::X86::kAVX512_DQ)) {
uint32_t usesAvx512 = InstInternal_usesAvx512(options, inst.extraReg(), regAnalysis);
uint32_t mustUseEvex = 0;
// Handle AVX vs AVX512 overlap.
//
// In general, non-AVX encoding is preferred, however, AVX encoded instructions that were initially provided
// as AVX-512 instructions must naturally prefer AVX-512 encoding, as that was the first one provided.
if (out->hasAny(Ext::kAVX,
Ext::kAVX_IFMA,
Ext::kAVX_NE_CONVERT,
Ext::kAVX_VNNI,
Ext::kAVX2,
Ext::kF16C,
Ext::kFMA)
&&
out->hasAny(Ext::kAVX512_BF16,
Ext::kAVX512_BW,
Ext::kAVX512_DQ,
Ext::kAVX512_F,
Ext::kAVX512_IFMA,
Ext::kAVX512_VNNI)) {
uint32_t useEvex = InstInternal_usesAvx512(options, inst.extraReg(), regAnalysis) | regAnalysis.highVecUsed;
switch (instId) {
// Special case: VPBROADCAST[B|D|Q|W] only supports r32/r64 with EVEX prefix.
case Inst::kIdVpbroadcastb:
case Inst::kIdVpbroadcastd:
case Inst::kIdVpbroadcastq:
case Inst::kIdVpbroadcastw:
mustUseEvex = opCount >= 2 && x86::Reg::isGp(operands[1]);
useEvex |= uint32_t(opCount >= 2 && x86::Reg::isGp(operands[1]));
break;
case Inst::kIdVcvtpd2dq:
case Inst::kIdVcvtpd2ps:
case Inst::kIdVcvttpd2dq:
mustUseEvex = opCount >= 2 && Reg::isYmm(operands[0]);
useEvex |= uint32_t(opCount >= 2 && Reg::isYmm(operands[0]));
break;
case Inst::kIdVgatherdpd:
@@ -1629,8 +1644,7 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
case Inst::kIdVpgatherdq:
case Inst::kIdVpgatherqd:
case Inst::kIdVpgatherqq:
if (opCount == 2)
mustUseEvex = true;
useEvex |= uint32_t(opCount == 2);
break;
// Special case: These instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode, then
@@ -1647,42 +1661,46 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
case Inst::kIdVpsrldq:
case Inst::kIdVpsrlq:
case Inst::kIdVpsrlw:
mustUseEvex = opCount >= 2 && operands[1].isMem();
useEvex |= uint32_t(opCount >= 2 && operands[1].isMem());
break;
// Special case: VPERMPD - AVX2 vs AVX512-F case.
case Inst::kIdVpermpd:
mustUseEvex = opCount >= 3 && !operands[2].isImm();
useEvex |= uint32_t(opCount >= 3 && !operands[2].isImm());
break;
// Special case: VPERMQ - AVX2 vs AVX512-F case.
case Inst::kIdVpermq:
mustUseEvex = opCount >= 3 && (operands[1].isMem() || !operands[2].isImm());
useEvex |= uint32_t(opCount >= 3 && (operands[1].isMem() || !operands[2].isImm()));
break;
}
if (!(usesAvx512 | mustUseEvex | regAnalysis.highVecUsed))
out->remove(CpuFeatures::X86::kAVX512_F, CpuFeatures::X86::kAVX512_BW, CpuFeatures::X86::kAVX512_DQ, CpuFeatures::X86::kAVX512_VL);
else
out->remove(CpuFeatures::X86::kAVX, CpuFeatures::X86::kAVX2, CpuFeatures::X86::kFMA, CpuFeatures::X86::kF16C);
}
}
if (instInfo.commonInfo().preferEvex() && !Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3))
useEvex = 1;
// Handle AVX_VNNI vs AVX512_VNNI overlap.
if (out->has(CpuFeatures::X86::kAVX512_VNNI)) {
// By default the AVX512_VNNI instruction should be used, because it was introduced first. However, VEX|VEX3
// prefix can be used to force AVX_VNNI instead.
uint32_t usesAvx512 = InstInternal_usesAvx512(options, inst.extraReg(), regAnalysis);
if (!usesAvx512 && Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3))
out->remove(CpuFeatures::X86::kAVX512_VNNI, CpuFeatures::X86::kAVX512_VL);
else
out->remove(CpuFeatures::X86::kAVX_VNNI);
if (useEvex) {
out->remove(Ext::kAVX,
Ext::kAVX_IFMA,
Ext::kAVX_NE_CONVERT,
Ext::kAVX_VNNI,
Ext::kAVX2,
Ext::kF16C,
Ext::kFMA);
}
else {
out->remove(Ext::kAVX512_BF16,
Ext::kAVX512_BW,
Ext::kAVX512_DQ,
Ext::kAVX512_F,
Ext::kAVX512_IFMA,
Ext::kAVX512_VL,
Ext::kAVX512_VNNI);
}
}
// Clear AVX512_VL if ZMM register is used.
if (regAnalysis.hasRegType(RegType::kX86_Zmm))
out->remove(CpuFeatures::X86::kAVX512_VL);
out->remove(Ext::kAVX512_VL);
}
return kErrorOk;

File diff suppressed because it is too large Load Diff

View File

@@ -126,6 +126,7 @@ enum EncodingId : uint32_t {
kEncodingVexMri, //!< VEX|EVEX [MRI].
kEncodingVexMri_Lx, //!< VEX|EVEX [MRI] (propagates VEX|EVEX.L if YMM used).
kEncodingVexMri_Vpextrw, //!< VEX|EVEX [MRI] (special case required by VPEXTRW instruction).
kEncodingVexMvr_Wx, //!< VEX|EVEX [MVR] (propagates VEX|EVEX.W if GPQ used).
kEncodingVexRm, //!< VEX|EVEX [RM].
kEncodingVexRm_ZDI, //!< VEX|EVEX [RM<ZDI>].
kEncodingVexRm_Wx, //!< VEX|EVEX [RM] (propagates VEX|EVEX.W if GPQ used).

View File

@@ -36,17 +36,27 @@ int main(int argc, char* argv[]) {
printf("Usage:\n");
printf(" --help Show usage only\n");
printf(" --arch=<ARCH> Select architecture to run ('all' by default)\n");
printf(" --verbose Log all instruction tests [%s]\n", settings.verbose ? "x" : " ");
printf(" --verbose Show only assembling errors [%s]\n", settings.verbose ? "x" : " ");
printf(" --validate Use instruction validation [%s]\n", settings.validate ? "x" : " ");
printf(" --arch=<ARCH> Select architecture to run ('all' by default)\n");
printf("\n");
printf("Architectures:\n");
#if !defined(ASMJIT_NO_X86)
printf(" --arch=x86 32-bit X86 architecture (X86)\n");
printf(" --arch=x64 64-bit X86 architecture (X86_64)\n");
#endif
#if !defined(ASMJIT_AARCH64)
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
#endif
printf("\n");
if (cmdLine.hasArg("--help"))
return 0;
const char* arch = cmdLine.valueOf("--arch", "all");
bool x86Failed = false;
bool x64Failed = false;
bool armFailed = false;
bool aarch64Failed = false;
#if !defined(ASMJIT_NO_X86)
@@ -62,7 +72,7 @@ int main(int argc, char* argv[]) {
aarch64Failed = !testA64Assembler(settings);
#endif
bool failed = x86Failed || x64Failed || aarch64Failed;
bool failed = x86Failed || x64Failed || armFailed || aarch64Failed;
if (failed) {
if (x86Failed)
@@ -71,6 +81,9 @@ int main(int argc, char* argv[]) {
if (x64Failed)
printf("** X64 test suite failed **\n");
if (armFailed)
printf("** ARM test suite failed **\n");
if (aarch64Failed)
printf("** AArch64 test suite failed **\n");

View File

@@ -52,7 +52,7 @@ public:
assembler.addDiagnosticOptions(asmjit::DiagnosticOptions::kValidateAssembler);
}
ASMJIT_NOINLINE bool testInstruction(const char* expectedOpcode, const char* s, uint32_t err) noexcept {
ASMJIT_NOINLINE bool testValidInstruction(const char* s, const char* expectedOpcode, asmjit::Error err) noexcept {
count++;
if (err) {
@@ -80,6 +80,29 @@ public:
prepare();
return true;
}
ASMJIT_NOINLINE bool testInvalidInstruction(const char* s, asmjit::Error expectedError, asmjit::Error err) noexcept {
count++;
if (err == asmjit::kErrorOk) {
printf(" !! %s passed, but should have failed with <%s> error\n", s, asmjit::DebugUtils::errorAsString(expectedError));
prepare();
return false;
}
if (err != asmjit::kErrorOk) {
printf(" !! %s failed with <%s>, but should have failed with <%s>\n", s, asmjit::DebugUtils::errorAsString(err), asmjit::DebugUtils::errorAsString(expectedError));
prepare();
return false;
}
if (settings.verbose)
printf(" OK [%s] <- %s\n", asmjit::DebugUtils::errorAsString(err), s);
passed++;
prepare();
return true;
}
};
#endif // ASMJIT_TEST_ASSEMBLER_H_INCLUDED

View File

@@ -17,7 +17,7 @@
using namespace asmjit;
#define TEST_INSTRUCTION(OPCODE, ...) \
tester.testInstruction(OPCODE, #__VA_ARGS__, tester.assembler.__VA_ARGS__)
tester.testValidInstruction(#__VA_ARGS__, OPCODE, tester.assembler.__VA_ARGS__)
static void ASMJIT_NOINLINE testA64AssemblerBase(AssemblerTester<a64::Assembler>& tester) noexcept {
using namespace a64;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,17 @@ int main(int argc, char* argv[]) {
printf("Usage:\n");
printf(" --help Show usage only\n");
printf(" --quick Decrease the number of iterations to make tests quicker\n");
printf(" --arch=<ARCH> Select architecture to run ('all' by default)\n");
printf(" --arch=<ARCH> Select architecture(s) to run ('all' by default)\n");
printf("\n");
printf("Architectures:\n");
#if !defined(ASMJIT_NO_X86)
printf(" --arch=x86 32-bit X86 architecture (X86)\n");
printf(" --arch=x64 64-bit X86 architecture (X86_64)\n");
#endif
#if !defined(ASMJIT_AARCH64)
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
#endif
printf("\n");
if (cmdLine.hasArg("--help"))

View File

@@ -41,6 +41,7 @@ static uint32_t calculateInstructionCount(asmjit::CodeHolder& code, asmjit::Arch
node = node->next();
}
code.reset();
return count;
}
#endif

View File

@@ -670,9 +670,9 @@ static void generateSseSequenceInternal(
cc.cvtpi2ps(xmmA, m);
cc.cvtsi2ss(xmmA, m);
cc.cvtss2si(gpd, m);
if (cc.is64Bit()) cc.cvtss2si(gpq, m);
cc.cvtss2si(gpz, m);
cc.cvttss2si(gpd, m);
if (cc.is64Bit()) cc.cvttss2si(gpq, m);
cc.cvttss2si(gpz, m);
cc.divps(xmmA, m);
cc.divss(xmmA, m);
cc.maxps(xmmA, m);
@@ -729,16 +729,16 @@ static void generateSseSequenceInternal(
cc.cvtps2dq(xmmA, m);
cc.cvtps2pd(xmmA, m);
cc.cvtsd2si(gpd, m);
if (cc.is64Bit()) cc.cvtsd2si(gpq, m);
cc.cvtsd2si(gpz, m);
cc.cvtsd2ss(xmmA, m);
cc.cvtsi2sd(xmmA, m);
cc.cvtss2sd(xmmA, m);
cc.cvtss2si(gpd, m);
if (cc.is64Bit()) cc.cvtss2si(gpq, m);
cc.cvtss2si(gpz, m);
cc.cvttpd2dq(xmmA, m);
cc.cvttps2dq(xmmA, m);
cc.cvttsd2si(gpd, m);
if (cc.is64Bit()) cc.cvttsd2si(gpq, m);
cc.cvttsd2si(gpz, m);
cc.divpd(xmmA, m);
cc.divsd(xmmA, m);
cc.maxpd(xmmA, m);

23
tools/gencommons.js Normal file
View File

@@ -0,0 +1,23 @@
// 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
let VERBOSE = false;
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 ERROR: ${msg}`);
throw new Error(msg);
}
exports.FATAL = FATAL;

270
tools/gencxx.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("./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;

View File

@@ -1,17 +1,12 @@
// [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("./gencommons.js");
const hasOwn = Object.prototype.hasOwnProperty;
const asmdb = core.asmdb;
@@ -19,7 +14,7 @@ const kIndent = core.kIndent;
const IndexedArray = core.IndexedArray;
const StringUtils = core.StringUtils;
const FAIL = core.FAIL;
const FATAL = commons.FATAL;
// ============================================================================
// [ArmDB]
@@ -170,7 +165,7 @@ class ArmTableGen extends core.TableGen {
}
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);
}

3
tools/tablegen-a64.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
node ./tablegen-a64.js

View File

@@ -1,3 +0,0 @@
#!/bin/sh
node ./tablegen-arm.js

View File

@@ -3,23 +3,15 @@
// 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 cxx = require("./gencxx.js");
const commons = require("./gencommons.js");
const core = require("./tablegen.js");
const asmdb = core.asmdb;
const kIndent = core.kIndent;
@@ -33,56 +25,28 @@ const IndexedArray = core.IndexedArray;
const hasOwn = Object.prototype.hasOwnProperty;
const disclaimer = StringUtils.disclaimer;
const FAIL = core.FAIL;
const DEBUG = core.DEBUG;
const DEBUG = commons.DEBUG;
const FATAL = commons.FATAL;
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));
// TODO: Fix these regressions:
// cvtsi2ss
// enqcmd
// ============================================================================
// [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/uw" , "RMI" , "66 69 /r iw" , "ANY OF=W SF=W ZF=U AF=U PF=U CF=W"],
["imul", "r32, id/ud" , "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 +59,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 +77,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 +131,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 +246,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 +265,7 @@ class GenUtils {
}
}
if (dbInst.attributes.Tsib)
if (dbInst.tsib)
f.Tsib = true;
if (dbInst.vsibReg)
@@ -289,12 +274,11 @@ class GenUtils {
if (dbInst.prefix === "VEX" || dbInst.prefix === "XOP")
f.Vex = true;
if (dbInst.prefix === "EVEX") {
f.Evex = true;
if (dbInst.extensions["AVX512_VNNI"])
if (dbInst.encodingPreference === "EVEX")
f.PreferEvex = true;
if (dbInst.prefix === "EVEX") {
f.Evex = true;
if (dbInst.kmask) f.Avx512K = true;
if (dbInst.zmask) f.Avx512Z = true;
@@ -418,7 +402,7 @@ class GenUtils {
}
}
static fixedRegOf(reg) {
static fixedRegOfRegName(reg) {
switch (reg) {
case "es" : return 1;
case "cs" : return 2;
@@ -447,11 +431,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 +469,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);
}
// --------------------------------------------------------------------------
@@ -514,7 +501,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);
@@ -547,7 +534,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);
}
@@ -830,7 +817,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 += "{";
@@ -968,7 +955,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);
@@ -1035,7 +1022,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";
@@ -1252,14 +1239,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.
@@ -1267,8 +1254,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;
@@ -1279,12 +1266,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;
}
@@ -1295,7 +1279,7 @@ 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 = "";
@@ -1410,6 +1394,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;
@@ -1422,8 +1408,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}`);
@@ -1592,7 +1579,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;
@@ -1676,29 +1665,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;
@@ -1718,6 +1687,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; }
@@ -1730,30 +1702,37 @@ class InstSignatureTable extends core.Task {
else if (reg) {
if (reg == "r8") {
op.flags["r8lo"] = 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);
}
@@ -1764,8 +1743,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;
@@ -1868,7 +1847,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,
@@ -1876,28 +1855,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;
@@ -2132,7 +2111,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;
}
}
@@ -2163,7 +2142,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
};
@@ -2197,10 +2176,7 @@ class InstRWInfoTable extends core.Task {
// 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") {
if (op.isReg())
d.fixed = GenUtils.fixedRegOf(op.reg);
else
d.fixed = GenUtils.fixedRegOf(op.mem);
d.fixed = GenUtils.fixedRegOf(op);
}
switch (instName) {
@@ -2232,7 +2208,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;
@@ -2320,7 +2296,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 : ""}:`);
@@ -2410,7 +2386,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);
}
}

View File

@@ -12,31 +12,22 @@
"use strict";
const VERBOSE = false;
// ============================================================================
// [Imports]
// ============================================================================
const fs = require("fs");
const commons = require("./gencommons.js");
const cxx = require("./gencxx.js");
const asmdb = require("../db");
exports.asmdb = asmdb;
exports.exp = asmdb.base.exp;
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;
}
}
// Try to import global 'asmdb' package as local package is not available.
return require("asmdb");
})();
exports.asmdb = asmdb;
const FATAL = commons.FATAL;
// ============================================================================
// [Constants]
@@ -50,27 +41,6 @@ exports.kIndent = kIndent;
exports.kJustify = kJustify;
exports.kAsmJitRoot = kAsmJitRoot;
// ============================================================================
// [Debugging]
// ============================================================================
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);
}
exports.FAIL = FAIL;
// ============================================================================
// [Lang]
// ============================================================================
@@ -162,7 +132,7 @@ class StringUtils {
static countOf(s, pattern) {
if (!pattern)
FAIL(`Pattern cannot be empty`);
FATAL(`Pattern cannot be empty`);
var n = 0;
var pos = 0;
@@ -175,11 +145,6 @@ class StringUtils {
return n;
}
static capitalize(s) {
s = String(s);
return !s ? s : s[0].toUpperCase() + s.substr(1);
}
static trimLeft(s) { return s.replace(/^\s+/, ""); }
static trimRight(s) { return s.replace(/\s+$/, ""); }
@@ -262,11 +227,15 @@ class StringUtils {
}
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;
if (line)
lines[i] = indentation + line;
}
}
@@ -278,10 +247,10 @@ class StringUtils {
var iEnd = s.indexOf(end);
if (iStart === -1)
FAIL(`StringUtils.extract(): Couldn't locate start mark '${start}'`);
FATAL(`StringUtils.extract(): Couldn't locate start mark '${start}'`);
if (iEnd === -1)
FAIL(`StringUtils.extract(): Couldn't locate end mark '${end}'`);
FATAL(`StringUtils.extract(): Couldn't locate end mark '${end}'`);
return s.substring(iStart + start.length, iEnd).trim();
}
@@ -291,10 +260,10 @@ class StringUtils {
var iEnd = s.indexOf(end);
if (iStart === -1)
FAIL(`StringUtils.inject(): Couldn't locate start mark '${start}'`);
FATAL(`StringUtils.inject(): Couldn't locate start mark '${start}'`);
if (iEnd === -1)
FAIL(`StringUtils.inject(): Couldn't locate end mark '${end}'`);
FATAL(`StringUtils.inject(): Couldn't locate end mark '${end}'`);
var nIndent = 0;
while (iStart > 0 && s[iStart-1] === " ") {
@@ -443,8 +412,8 @@ class CxxUtils {
if (!fn)
fn = nop;
var out = "";
for (var k in obj) {
let out = "";
for (let k in obj) {
if (obj[k])
out += (out ? " | " : "") + fn(k);
}
@@ -536,7 +505,7 @@ class IndexedString {
format(indent, justify) {
if (this.size === -1)
FAIL(`IndexedString.format(): not indexed yet, call index()`);
FATAL(`IndexedString.format(): not indexed yet, call index()`);
const array = this.array;
if (!justify) justify = 0;
@@ -564,16 +533,16 @@ class IndexedString {
getSize() {
if (this.size === -1)
FAIL(`IndexedString.getSize(): Not indexed yet, call index()`);
FATAL(`IndexedString.getSize(): Not indexed yet, call index()`);
return this.size;
}
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];
}
@@ -585,23 +554,13 @@ exports.IndexedString = IndexedString;
// [InstructionNameData]
// ============================================================================
function decimalToHexString(number, pad) {
if (number < 0)
number = 0xFFFFFFFF + number + 1;
let s = number.toString(16).toUpperCase();
if (pad)
s = s.padStart(pad, "0")
return s;
}
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
FAIL(`Character '${c}' cannot be encoded into a 5-bit string`);
FATAL(`Character '${c}' cannot be encoded into a 5-bit string`);
}
class InstructionNameData {
@@ -746,11 +705,11 @@ class InstructionNameData {
formatIndexTable(tableName) {
if (this.size === -1)
FAIL(`IndexedString.formatIndexTable(): Not indexed yet, call index()`);
FATAL(`IndexedString.formatIndexTable(): Not indexed yet, call index()`);
let s = "";
for (let i = 0; i < this.primaryTable.length; i++) {
s += "0x" + decimalToHexString(this.primaryTable[i], 8);
s += cxx.Utils.toHex(this.primaryTable[i], 8);
s += i !== this.primaryTable.length - 1 ? "," : " ";
s += " // " + this.indexComment[i] + "\n";
}
@@ -760,7 +719,7 @@ class InstructionNameData {
formatStringTable(tableName) {
if (this.size === -1)
FAIL(`IndexedString.formatStringTable(): Not indexed yet, call index()`);
FATAL(`IndexedString.formatStringTable(): Not indexed yet, call index()`);
let s = "";
for (let i = 0; i < this.stringTable.length; i += 80) {
@@ -775,17 +734,17 @@ class InstructionNameData {
getSize() {
if (this.size === -1)
FAIL(`IndexedString.getSize(): Not indexed yet, call index()`);
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];
}
@@ -855,7 +814,7 @@ class Task {
}
run() {
FAIL("Task.run(): Must be reimplemented");
FATAL("Task.run(): Must be reimplemented");
}
}
exports.Task = Task;
@@ -917,7 +876,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;
}
@@ -938,7 +897,7 @@ class TableGen {
}
if (!done)
FAIL(`TableGen.inject(): Cannot find '${key}'`);
FATAL(`TableGen.inject(): Cannot find '${key}'`);
if (size)
this.tableSizes[key] = size;
@@ -952,14 +911,14 @@ class TableGen {
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);
@@ -1004,7 +963,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);
@@ -1068,7 +1027,7 @@ class IdEnum extends Task {
}
comment(name) {
FAIL("IdEnum.comment(): Must be reimplemented");
FATAL("IdEnum.comment(): Must be reimplemented");
}
run() {
@@ -1121,7 +1080,7 @@ class NameTable extends Task {
const index = name.charCodeAt(0) - 'a'.charCodeAt(0);
if (index < 0 || index >= 26)
FAIL(`TableGen.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`);
FATAL(`TableGen.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`);
if (instFirst[index] === undefined)
instFirst[index] = `Inst::kId${inst.enum}`;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
set -e
node ./tablegen-arm.js $@
node ./tablegen-a64.js $@
node ./tablegen-x86.js $@