mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-16 20:17:05 +03:00
[ABI] Updated instruction DB, operands, and minor API changes
This changeset contains an updated instruction database that brings ARM32 instructions for the first time. It also updates instruction database tooling especially for ARM64, which will also be used by ARM32 generator. Additionally, new operan has been added, which represents a register list as used by ARM32 instruction set. Other minor changes are related to ARM - some stuff had to be moved to a64 namespace from arm namespace as it's incompatible between 32-bit and 64-bit ISA.
This commit is contained in:
@@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
|
||||
cmake_policy(PUSH)
|
||||
|
||||
if(POLICY CMP0063)
|
||||
if (POLICY CMP0063)
|
||||
cmake_policy(SET CMP0063 NEW) # Honor visibility properties.
|
||||
endif()
|
||||
|
||||
if(POLICY CMP0092)
|
||||
if (POLICY CMP0092)
|
||||
cmake_policy(SET CMP0092 NEW) # Don't add -W3 warning level by default.
|
||||
endif()
|
||||
|
||||
@@ -33,15 +33,13 @@ if (DEFINED ASMJIT_BUILD_STATIC)
|
||||
set(ASMJIT_STATIC "${ASMJIT_BUILD_STATIC}")
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration
|
||||
# ======================
|
||||
# AsmJit - Configuration - Build
|
||||
# ==============================
|
||||
|
||||
# AsmJit testing.
|
||||
if (NOT DEFINED ASMJIT_TEST)
|
||||
set(ASMJIT_TEST FALSE)
|
||||
endif()
|
||||
|
||||
# AsmJit build options
|
||||
if (NOT DEFINED ASMJIT_EMBED)
|
||||
set(ASMJIT_EMBED FALSE)
|
||||
endif()
|
||||
@@ -54,15 +52,22 @@ if (NOT DEFINED ASMJIT_SANITIZE)
|
||||
set(ASMJIT_SANITIZE FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_NATVIS)
|
||||
set(ASMJIT_NO_NATVIS FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_CUSTOM_FLAGS)
|
||||
set(ASMJIT_NO_CUSTOM_FLAGS FALSE)
|
||||
endif()
|
||||
|
||||
# AsmJit backends selection.
|
||||
if (NOT DEFINED ASMJIT_NO_NATVIS)
|
||||
set(ASMJIT_NO_NATVIS FALSE)
|
||||
endif()
|
||||
|
||||
# EMBED implies STATIC.
|
||||
if (ASMJIT_EMBED AND NOT ASMJIT_STATIC)
|
||||
set(ASMJIT_STATIC TRUE)
|
||||
endif()
|
||||
|
||||
# AsmJit - Configuration - Backend
|
||||
# ================================
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_X86)
|
||||
set(ASMJIT_NO_X86 FALSE)
|
||||
endif()
|
||||
@@ -75,7 +80,9 @@ if (NOT DEFINED ASMJIT_NO_FOREIGN)
|
||||
set(ASMJIT_NO_FOREIGN FALSE)
|
||||
endif()
|
||||
|
||||
# AsmJit features selection.
|
||||
# AsmJit - Configuration - Features
|
||||
# =================================
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_DEPRECATED)
|
||||
set(ASMJIT_NO_DEPRECATED FALSE)
|
||||
endif()
|
||||
@@ -89,19 +96,19 @@ if (NOT DEFINED ASMJIT_NO_JIT)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_TEXT)
|
||||
set(ASMJIT_NO_TEXT ${ASMJIT_NO_TEXT})
|
||||
set(ASMJIT_NO_TEXT FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_LOGGING)
|
||||
set(ASMJIT_NO_LOGGING FALSE)
|
||||
set(ASMJIT_NO_LOGGING ${ASMJIT_NO_TEXT})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_VALIDATION)
|
||||
set(ASMJIT_NO_VALIDATION ${ASMJIT_NO_VALIDATION})
|
||||
set(ASMJIT_NO_VALIDATION FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_INTROSPECTION)
|
||||
set(ASMJIT_NO_INTROSPECTION ${ASMJIT_NO_INTROSPECTION})
|
||||
set(ASMJIT_NO_INTROSPECTION FALSE)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_BUILDER)
|
||||
@@ -109,16 +116,17 @@ if (NOT DEFINED ASMJIT_NO_BUILDER)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ASMJIT_NO_COMPILER)
|
||||
set(ASMJIT_NO_BUILDER ${ASMJIT_NO_BUILDER})
|
||||
if (ASMJIT_NO_BUILDER OR ASMJIT_NO_INTROSPECTION)
|
||||
set(ASMJIT_NO_COMPILER TRUE)
|
||||
else()
|
||||
set(ASMJIT_NO_COMPILER FALSE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# EMBED implies STATIC.
|
||||
if (ASMJIT_EMBED AND NOT ASMJIT_STATIC)
|
||||
set(ASMJIT_STATIC TRUE)
|
||||
endif()
|
||||
# AsmJit - Configuration - CMake Introspection
|
||||
# ============================================
|
||||
|
||||
set(ASMJIT_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Location of 'asmjit'")
|
||||
|
||||
set(ASMJIT_TEST "${ASMJIT_TEST}" CACHE BOOL "Build 'asmjit' test applications")
|
||||
set(ASMJIT_EMBED "${ASMJIT_EMBED}" CACHE BOOL "Embed 'asmjit' library (no targets)")
|
||||
set(ASMJIT_STATIC "${ASMJIT_STATIC}" CACHE BOOL "Build 'asmjit' library as static")
|
||||
@@ -359,21 +367,21 @@ else()
|
||||
set(ASMJIT_TARGET_TYPE "SHARED")
|
||||
endif()
|
||||
|
||||
foreach(build_option ASMJIT_STATIC
|
||||
foreach(build_option # AsmJit build options.
|
||||
ASMJIT_STATIC
|
||||
ASMJIT_NO_DEPRECATED
|
||||
# AsmJit backends selection.
|
||||
ASMJIT_NO_X86
|
||||
ASMJIT_NO_AARCH64
|
||||
ASMJIT_NO_FOREIGN
|
||||
# AsmJit features selection.
|
||||
ASMJIT_NO_DEPRECATED
|
||||
ASMJIT_NO_SHM_OPEN
|
||||
ASMJIT_NO_JIT
|
||||
ASMJIT_NO_TEXT
|
||||
ASMJIT_NO_LOGGING
|
||||
ASMJIT_NO_BUILDER
|
||||
ASMJIT_NO_COMPILER
|
||||
ASMJIT_NO_INTROSPECTION
|
||||
ASMJIT_NO_VALIDATION
|
||||
ASMJIT_NO_INTROSPECTION)
|
||||
ASMJIT_NO_BUILDER
|
||||
ASMJIT_NO_COMPILER)
|
||||
if (${build_option})
|
||||
List(APPEND ASMJIT_CFLAGS "-D${build_option}")
|
||||
List(APPEND ASMJIT_PRIVATE_CFLAGS "-D${build_option}")
|
||||
@@ -384,7 +392,7 @@ endforeach()
|
||||
# =======================
|
||||
|
||||
if (WIN32)
|
||||
if(CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
|
||||
if (CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
|
||||
set(ASMJIT_LINKER_SUPPORTS_NATVIS TRUE)
|
||||
endif()
|
||||
endif()
|
||||
@@ -439,6 +447,8 @@ set(ASMJIT_SRC_LIST
|
||||
asmjit/core/globals.h
|
||||
asmjit/core/inst.cpp
|
||||
asmjit/core/inst.h
|
||||
asmjit/core/instdb.cpp
|
||||
asmjit/core/instdb_p.h
|
||||
asmjit/core/jitallocator.cpp
|
||||
asmjit/core/jitallocator.h
|
||||
asmjit/core/jitruntime.cpp
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
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.
|
||||
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 file. 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
|
||||
* `isa_aarch32.json` - provides AArch32 instruction data (A32/T16/T32 encoding)
|
||||
* `isa_aarch64.json` - provides AArch64 instruction data (A64 encoding)
|
||||
* `isa_aarch64_sme.json` - provides AArch64 SME instruction data (work-in-progress)
|
||||
|
||||
To Be Documented
|
||||
----------------
|
||||
|
||||
@@ -29,14 +29,14 @@ const arm = $scope[$as] = dict();
|
||||
// Database
|
||||
// ========
|
||||
|
||||
arm.dbName = "isa_arm.json";
|
||||
arm.dbName = "isa_aarch32.json";
|
||||
|
||||
// asmdb.arm.Utils
|
||||
// ===============
|
||||
// asmdb.aarch32.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.
|
||||
// of all registers as many instructions accept only LO (r0..r7) registers.
|
||||
const FieldInfo = {
|
||||
"P" : { "bits": 1 },
|
||||
"U" : { "bits": 1 },
|
||||
@@ -56,6 +56,7 @@ const FieldInfo = {
|
||||
"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 },
|
||||
@@ -70,17 +71,22 @@ const FieldInfo = {
|
||||
"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 },
|
||||
"SdList": { "bits": 4, "read": false, "write": true , "list": 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 },
|
||||
"SsList": { "bits": 4, "read": true , "write": false , "list": true },
|
||||
|
||||
"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 },
|
||||
"DdList": { "bits": 4, "read": false, "write": true , "list": true },
|
||||
"Dx" : { "bits": 4, "read": true , "write": true },
|
||||
"Dx2" : { "bits": 4, "read": true , "write": true },
|
||||
"Dn" : { "bits": 4, "read": true , "write": false },
|
||||
@@ -92,18 +98,18 @@ const FieldInfo = {
|
||||
"Ds2" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds3" : { "bits": 4, "read": true , "write": false },
|
||||
"Ds4" : { "bits": 4, "read": true , "write": false },
|
||||
"DsList": { "bits": 4, "read": true , "write": false , "list": true },
|
||||
|
||||
"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;
|
||||
@@ -192,10 +198,16 @@ function decomposeOperand(s) {
|
||||
const elementSuffix = "[#i]";
|
||||
let element = null;
|
||||
let consecutive = 0;
|
||||
let userRegList = false;
|
||||
|
||||
if (s.endsWith("^")) {
|
||||
userRegList = true;
|
||||
s = s.substring(0, s.length - 1);
|
||||
}
|
||||
|
||||
if (s.endsWith(elementSuffix)) {
|
||||
element = "#i";
|
||||
s = s.substr(0, s.length - elementSuffix.length);
|
||||
s = s.substring(0, s.length - elementSuffix.length);
|
||||
}
|
||||
|
||||
if (s.endsWith("++")) {
|
||||
@@ -219,7 +231,8 @@ function decomposeOperand(s) {
|
||||
data : s,
|
||||
element : element,
|
||||
restrict: restrict,
|
||||
consecutive: consecutive
|
||||
consecutive: consecutive,
|
||||
userRegList: true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -238,8 +251,8 @@ function splitOpcodeFields(s) {
|
||||
return out.map((field) => { return field.trim(); });
|
||||
}
|
||||
|
||||
// asmdb.arm.Operand
|
||||
// =================
|
||||
// asmdb.aarch32.Operand
|
||||
// =====================
|
||||
|
||||
// ARM operand.
|
||||
class Operand extends base.Operand {
|
||||
@@ -267,17 +280,44 @@ class Operand extends base.Operand {
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
isRelative() {
|
||||
if (this.type === "imm")
|
||||
return this.name === "relA" || this.name === "relS" || this.name === "relZ";
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
arm.Operand = Operand;
|
||||
|
||||
// asmdb.arm.Instruction
|
||||
// =====================
|
||||
// asmdb.aarch32.Instruction
|
||||
// =========================
|
||||
|
||||
function patternFromOperand(key) {
|
||||
return key;
|
||||
// return key.replace(/\b(?:[RVDS](?:d|s|n|m|x|x2))\b/, "R");
|
||||
}
|
||||
|
||||
// Rewrite a memory operand expression (either base or index) to a simplified one, which is okay
|
||||
// to be generated as C++ expression. In general, we want to simplify != to a more favorable code.
|
||||
function simplifyMemoryExpression(e) {
|
||||
if (e.type === "binary" && e.op === "!=" && e.right.type === "var") {
|
||||
// Rewrite A != PC to A < PC
|
||||
if (e.right.name === "PC") { e.op = "<"; }
|
||||
|
||||
// Rewrite A != HI to A < 8
|
||||
if (e.right.name === "HI") { e.op = "<"; e.right = exp.Imm(8); }
|
||||
|
||||
// Rewrite A != XX to A < SP || A == LR
|
||||
if (e.right.name === "XX") {
|
||||
return exp.Or(exp.Lt(e.left, exp.Var("SP")),
|
||||
exp.Eq(e.left.clone(), exp.Var("LR")));
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// ARM instruction.
|
||||
class Instruction extends base.Instruction {
|
||||
constructor(db, data) {
|
||||
@@ -482,13 +522,14 @@ class Instruction extends base.Instruction {
|
||||
|
||||
const m = part.match(/^([A-Za-z]\w*)/);
|
||||
if (m.length < part.length) {
|
||||
op.base.exp = exp.parse(part);
|
||||
op.base.exp = simplifyMemoryExpression(exp.parse(part));
|
||||
op.base.field = m[1];
|
||||
}
|
||||
}
|
||||
else if (part.startsWith("#")) {
|
||||
let p = part.substring(1);
|
||||
let u = "1";
|
||||
let alwaysNegative = false;
|
||||
|
||||
let offExp = null;
|
||||
let offMul = 1;
|
||||
@@ -498,6 +539,11 @@ class Instruction extends base.Instruction {
|
||||
p = p.substring(3);
|
||||
}
|
||||
|
||||
if (p.startsWith("-")) {
|
||||
alwaysNegative = false;
|
||||
p = p.substring(1);
|
||||
}
|
||||
|
||||
const expMatch = p.match(/^([A-Za-z]\w*)==/);
|
||||
if (expMatch) {
|
||||
offExp = exp.parse(p);
|
||||
@@ -515,6 +561,7 @@ class Instruction extends base.Instruction {
|
||||
op.offset.u = u;
|
||||
op.offset.exp = offExp;
|
||||
op.offset.mul = offMul;
|
||||
op.offset.negative = alwaysNegative;
|
||||
}
|
||||
else {
|
||||
let p = part;
|
||||
@@ -531,7 +578,7 @@ class Instruction extends base.Instruction {
|
||||
|
||||
const m = p.match(/^([A-Za-z]\w*)/);
|
||||
if (m.length < p.length) {
|
||||
op.index.exp = exp.parse(p);
|
||||
op.index.exp = simplifyMemoryExpression(exp.parse(p));
|
||||
op.index.field = m[1];
|
||||
}
|
||||
}
|
||||
@@ -858,8 +905,8 @@ class Instruction extends base.Instruction {
|
||||
}
|
||||
arm.Instruction = Instruction;
|
||||
|
||||
// asmdb.arm.ISA
|
||||
// =============
|
||||
// asmdb.aarch32.ISA
|
||||
// =================
|
||||
|
||||
function mergeGroupData(data, group) {
|
||||
for (let k in group) {
|
||||
@@ -921,7 +968,7 @@ class ISA extends base.ISA {
|
||||
hasOwn.call(obj, "t16") ? "t16" : "";
|
||||
|
||||
if (!encoding)
|
||||
FAIL(`Instrution ${names.join("/")} doesn't encoding, it must provide either a32, t32, or t16 field`);
|
||||
FAIL(`Instruction ${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);
|
||||
@@ -938,4 +985,4 @@ class ISA extends base.ISA {
|
||||
arm.ISA = ISA;
|
||||
|
||||
}).apply(this, typeof module === "object" && module && module.exports
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "arm"]);
|
||||
? [module, "exports"] : [this.asmdb || (this.asmdb = {}), "aarch32"]);
|
||||
@@ -36,7 +36,7 @@ arm.dbName = "isa_aarch64.json";
|
||||
|
||||
// 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.
|
||||
// of all registers as many instructions accept only LO (r0..r7) registers.
|
||||
const FieldInfo = {
|
||||
"P" : { "bits": 1 },
|
||||
"U" : { "bits": 1 },
|
||||
|
||||
16
db/base.js
16
db/base.js
@@ -205,7 +205,7 @@ class Operand {
|
||||
|
||||
toString() { return this.data; }
|
||||
|
||||
isReg() { return !!this.reg; }
|
||||
isReg() { return !!this.reg && this.type !== "reg-list"; }
|
||||
isMem() { return !!this.mem; }
|
||||
isImm() { return !!this.imm; }
|
||||
isRel() { return !!this.rel; }
|
||||
@@ -259,6 +259,20 @@ class Instruction {
|
||||
return out;
|
||||
}
|
||||
|
||||
get operandCount() {
|
||||
return this.operands.length;
|
||||
}
|
||||
|
||||
get minimumOperandCount() {
|
||||
const count = this.operands.length;
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (this.operands[i].optional) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
_assignAttribute(key, value) {
|
||||
switch (key) {
|
||||
case "ext":
|
||||
|
||||
165
db/exp.js
165
db/exp.js
@@ -87,6 +87,7 @@ class ExpNode {
|
||||
|
||||
info() { return null; }
|
||||
clone() { throw new Error("ExpNode.clone() must be overridden"); }
|
||||
evaluate(ctx) { throw new Error("ExpNode.evaluate() must be overridden"); }
|
||||
toString(ctx) { throw new Error("ExpNode.toString() must be overridden"); }
|
||||
}
|
||||
|
||||
@@ -97,6 +98,7 @@ class ImmNode extends ExpNode {
|
||||
}
|
||||
|
||||
clone() { return new ImmNode(this.imm); }
|
||||
evaluate(ctx) { return this.imm; }
|
||||
toString(ctx) { return ctx ? ctx.stringifyImmediate(this.imm) : String(this.imm); }
|
||||
}
|
||||
|
||||
@@ -106,7 +108,8 @@ class VarNode extends ExpNode {
|
||||
this.name = name || "";
|
||||
}
|
||||
|
||||
clone() { return new VarNode(this.var); }
|
||||
clone() { return new VarNode(this.name); }
|
||||
evaluate(ctx) { return ctx.variable(this.name); }
|
||||
toString(ctx) { return ctx ? ctx.stringifyVariable(this.name) : String(this.name); }
|
||||
}
|
||||
|
||||
@@ -117,7 +120,14 @@ class CallNode extends ExpNode {
|
||||
this.args = args || [];
|
||||
}
|
||||
|
||||
clone() { return new CallNode(this.name, this.args.map(function(arg) { return arg.clone(); })); }
|
||||
clone() {
|
||||
return new CallNode(this.name, this.args.map(function(arg) { return arg.clone(); }));
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const evaluatedArgs = this.args.map(function(arg) { return arg.evaluate(ctx); });
|
||||
return ctx.function(this.name, evaluatedArgs);
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
if (this.name === "$bit") {
|
||||
@@ -143,8 +153,23 @@ class UnaryNode extends ExpNode {
|
||||
this.child = child || null;
|
||||
}
|
||||
|
||||
info() { return kUnaryOperators[this.op]; }
|
||||
clone() { return new UnaryNode(this.op, this.left ? this.left.clone() : null); }
|
||||
info() {
|
||||
return kUnaryOperators[this.op];
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new UnaryNode(this.op, this.left ? this.left.clone() : null);
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const val = this.child.evaluate(ctx);
|
||||
switch (this.op) {
|
||||
case "-": return (-val);
|
||||
case "~": return (~val);
|
||||
case "!": return (val ? 0 : 1);
|
||||
default : return ctx.unary(this.op, val);
|
||||
}
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
return this.info().emit.replace(/@1/g, () => {
|
||||
@@ -166,8 +191,40 @@ class BinaryNode extends ExpNode {
|
||||
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); }
|
||||
info() {
|
||||
return kBinaryOperators[this.op];
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new BinaryNode(this.op, this.left ? this.left.clone() : null, this.right ? this.right.clone() : null);
|
||||
}
|
||||
|
||||
evaluate(ctx) {
|
||||
const left = this.left.evaluate(ctx);
|
||||
const right = this.right.evaluate(ctx);
|
||||
|
||||
switch (this.op) {
|
||||
case "-" : return left - right;
|
||||
case "+" : return left + right;
|
||||
case "*" : return left * right;
|
||||
case "/" : return (left / right)|0;
|
||||
case "%" : return (left % right)|0;
|
||||
case "&" : return left & right;
|
||||
case "|" : return left | right;
|
||||
case "^" : return left ^ right;
|
||||
case "<<": return left << right;
|
||||
case ">>": return left >> right;
|
||||
case "==": return left == right ? 1 : 0;
|
||||
case "!=": return left != right ? 1 : 0;
|
||||
case "<" : return left < right ? 1 : 0;
|
||||
case "<=": return left <= right ? 1 : 0;
|
||||
case ">" : return left > right ? 1 : 0;
|
||||
case ">=": return left >= right ? 1 : 0;
|
||||
case "&&": return left && right ? 1 : 0;
|
||||
case "||": return left || right ? 1 : 0;
|
||||
default : return ctx.binary(this.op, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
toString(ctx) {
|
||||
return this.info().emit.replace(/@[1-2]/g, (p) => {
|
||||
@@ -184,8 +241,6 @@ 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); }
|
||||
|
||||
@@ -207,7 +262,8 @@ 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
|
||||
// --------------------
|
||||
@@ -256,7 +312,44 @@ function newToken(type, position, data, 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;
|
||||
const reNumValue = /(?:(?:\d*\.\d+|\d+)(?:[E|e][+|-]?\d+)?)/g;
|
||||
|
||||
function parseHex(source, from) {
|
||||
let i = from;
|
||||
let number = 0;
|
||||
|
||||
while (i < source.length) {
|
||||
let c = source.charCodeAt(i);
|
||||
let n = 0;
|
||||
|
||||
if (c >= '0'.charCodeAt(0) && c <= '9'.charCodeAt(0)) {
|
||||
n = c - '0'.charCodeAt(0);
|
||||
}
|
||||
else if (c >= 'a'.charCodeAt(0) && c <= 'f'.charCodeAt(0)) {
|
||||
n = c - 'a'.charCodeAt(0) + 10;
|
||||
}
|
||||
else if (c >= 'A'.charCodeAt(0) && c <= 'F'.charCodeAt(0)) {
|
||||
n = c - 'A'.charCodeAt(0) + 10;
|
||||
}
|
||||
else if (c >= 'g'.charCodeAt(0) && c <= 'z'.charCodeAt(0) || c >= 'g'.charCodeAt(0) && c <= 'Z'.charCodeAt(0)) {
|
||||
throwExpressionError(`Invalid hex number 0x${source.substring(from, i + 1)}`);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
number = (number << 4) | n;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i === from)
|
||||
throwExpressionError(`Invalid number starting with 0x`);
|
||||
|
||||
return {
|
||||
number: number,
|
||||
end: i
|
||||
};
|
||||
}
|
||||
|
||||
function tokenize(source) {
|
||||
const len = source.length;
|
||||
@@ -268,22 +361,33 @@ function tokenize(source) {
|
||||
let c, cat; // Current character code and category.
|
||||
|
||||
while (i < len) {
|
||||
cat = Category(c = source.charCodeAt(i));
|
||||
c = source.charCodeAt(i);
|
||||
cat = Category(c);
|
||||
|
||||
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;
|
||||
// Hex number.
|
||||
if (c === '0'.charCodeAt(0) && i + 1 < len && source.charCodeAt(i + 1) === 'x'.charCodeAt(0)) {
|
||||
const status = parseHex(source, i + 2);
|
||||
tokens.push(newToken(kTokenValue, i, source.substring(i, status.end), status.number));
|
||||
i = status.end;
|
||||
}
|
||||
else {
|
||||
if (n >= 0 && tokens[n].data === "." && source[i - 1] === ".") {
|
||||
tokens.length = n;
|
||||
i--;
|
||||
}
|
||||
|
||||
reNumValue.lastIndex = i;
|
||||
data = reNumValue.exec(source)[0];
|
||||
|
||||
tokens.push(newToken(kTokenValue, i, data, parseFloat(data)));
|
||||
i += data.length;
|
||||
}
|
||||
}
|
||||
else if (cat === kCharAlpha) {
|
||||
start = i;
|
||||
@@ -623,6 +727,29 @@ $scope[$as] = {
|
||||
Call: Call,
|
||||
Unary: Unary,
|
||||
Binary: Binary,
|
||||
|
||||
Negate: Negate,
|
||||
BitNot: BitNot,
|
||||
|
||||
Add: Add,
|
||||
Sub: Sub,
|
||||
Mul: Mul,
|
||||
Div: Div,
|
||||
Mod: Mod,
|
||||
Shl: Shl,
|
||||
Shr: Shr,
|
||||
BitAnd: BitAnd,
|
||||
BitOr: BitOr,
|
||||
BitXor: BitXor,
|
||||
Eq: Eq,
|
||||
Ne: Ne,
|
||||
Lt: Lt,
|
||||
Le: Le,
|
||||
Gt: Gt,
|
||||
Ge: Ge,
|
||||
And: And,
|
||||
Or: Or,
|
||||
|
||||
Visitor: Visitor,
|
||||
ExpressionError: ExpressionError,
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"use strict";
|
||||
|
||||
exports.base = require("./base.js");
|
||||
exports.arm = require("./arm.js");
|
||||
exports.aarch32 = require("./aarch32.js");
|
||||
exports.aarch64 = require("./aarch64.js");
|
||||
exports.x86 = require("./x86.js");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -139,70 +139,70 @@
|
||||
{"inst": "ldaxr Xd, [Xn|SP]" , "op": "11001000|010|11111|1|11111|Rn|Rd"},
|
||||
{"inst": "ldaxrb Wd, [Xn|SP]" , "op": "00001000|010|11111|1|11111|Rn|Rd"},
|
||||
{"inst": "ldaxrh Xd, [Xn|SP]" , "op": "01001000|010|11111|1|11111|Rn|Rd"},
|
||||
{"inst": "ldnp Wd, Wd2, [Xn|SP, #soff*4]" , "op": "00101000|01|soff:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldnp Xd, Xd2, [Xn|SP, #soff*8]" , "op": "10101000|01|soff:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldp Wd, Wd2, [Xn|SP, #soff*4]{@}{!}" , "op": "0010100|!post|W|1|soff:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldp Xd, Xd2, [Xn|SP, #soff*8]{@}{!}" , "op": "1010100|!post|W|1|soff:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldpsw Xd, Xd2, [Xn|SP, #soff*4]{@}{!}" , "op": "0110100|!post|W|1|soff:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #zoff*4]" , "op": "10111001|01|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #zoff*8]" , "op": "11111001|01|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #soff*4]@" , "op": "10111000|010|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #soff*8]@" , "op": "11111000|010|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #soff*4]!" , "op": "10111000|010|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #soff*8]!" , "op": "11111000|010|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldnp Wd, Wd2, [Xn|SP, #offS*4]" , "op": "00101000|01|offS:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldnp Xd, Xd2, [Xn|SP, #offS*8]" , "op": "10101000|01|offS:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldp Wd, Wd2, [Xn|SP, #offS*4]{@}{!}" , "op": "0010100|!post|W|1|offS:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldp Xd, Xd2, [Xn|SP, #offS*8]{@}{!}" , "op": "1010100|!post|W|1|offS:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldpsw Xd, Xd2, [Xn|SP, #offS*4]{@}{!}" , "op": "0110100|!post|W|1|offS:7|Rd2|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #offZ*4]" , "op": "10111001|01|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #offZ*8]" , "op": "11111001|01|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #offS*4]@" , "op": "10111000|010|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #offS*8]@" , "op": "11111000|010|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, #offS*4]!" , "op": "10111000|010|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldr Xd, [Xn|SP, #offS*8]!" , "op": "11111000|010|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "10111000|011|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDR(iop, n)"},
|
||||
{"inst": "ldr Xd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "11111000|011|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDR(iop, n)"},
|
||||
{"inst": "ldr Wd, [PC, #soff*4]" , "op": "00011000|soff:19|Rd"},
|
||||
{"inst": "ldr Xd, [PC, #soff*4]" , "op": "01011000|soff:19|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #zoff]" , "op": "00111001|01|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #soff]@" , "op": "00111000|010|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #soff]!" , "op": "00111000|010|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldr Wd, [PC, #offS*4]" , "op": "00011000|offS:19|Rd"},
|
||||
{"inst": "ldr Xd, [PC, #offS*4]" , "op": "01011000|offS:19|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #offZ]" , "op": "00111001|01|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #offS]@" , "op": "00111000|010|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, #offS]!" , "op": "00111000|010|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrb Wd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111000|011|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRB(iop, n)"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #zoff*2]" , "op": "01111001|01|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #soff*2]@" , "op": "01111000|010|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #soff*2]!" , "op": "01111000|010|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #offZ*2]" , "op": "01111001|01|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #offS*2]@" , "op": "01111000|010|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, #offS*2]!" , "op": "01111000|010|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrh Wd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111000|011|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRH(iop, n)"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #zoff]" , "op": "00111001|11|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #zoff]" , "op": "00111001|10|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #soff]@" , "op": "00111000|110|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #soff]@" , "op": "00111000|100|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #soff]!" , "op": "00111000|110|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #soff]!" , "op": "00111000|100|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #offZ]" , "op": "00111001|11|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #offZ]" , "op": "00111001|10|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #offS]@" , "op": "00111000|110|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #offS]@" , "op": "00111000|100|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, #offS]!" , "op": "00111000|110|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, #offS]!" , "op": "00111000|100|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsb Wd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111000|111|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRB(iop, n)"},
|
||||
{"inst": "ldrsb Xd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111000|101|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRB(iop, n)"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #zoff*2]" , "op": "01111001|11|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #zoff*2]" , "op": "01111001|10|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #soff*2]@" , "op": "01111000|110|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #soff*2]@" , "op": "01111000|100|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #soff*2]!" , "op": "01111000|110|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #soff*2]!" , "op": "01111000|100|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #offZ*2]" , "op": "01111001|11|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #offZ*2]" , "op": "01111001|10|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #offS*2]@" , "op": "01111000|110|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #offS*2]@" , "op": "01111000|100|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, #offS*2]!" , "op": "01111000|110|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, #offS*2]!" , "op": "01111000|100|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsh Wd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111000|111|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRH(iop, n)"},
|
||||
{"inst": "ldrsh Xd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111000|101|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRH(iop, n)"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #zoff*4]" , "op": "10111001|10|zoff:12|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #soff*4]@" , "op": "10111000|100|soff:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #soff*4]!" , "op": "10111000|100|soff:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [PC, #soff*4]" , "op": "10011000|soff:19|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #offZ*4]" , "op": "10111001|10|offZ:12|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #offS*4]@" , "op": "10111000|100|offS:9|01|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, #offS*4]!" , "op": "10111000|100|offS:9|11|Rn|Rd"},
|
||||
{"inst": "ldrsw Xd, [PC, #offS*4]" , "op": "10011000|offS:19|Rd"},
|
||||
{"inst": "ldrsw Xd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "10111000|101|Rm|option:3|s:1|10|Rn|Rd" , "imm": "ImmLDRW(iop, n)"},
|
||||
{"inst": "ldtr Wd, [Xn|SP, #soff]" , "op": "10111000|010|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtr Xd, [Xn|SP, #soff]" , "op": "11111000|010|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrb Wd, [Xn|SP, #soff]" , "op": "00111000|010|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrh Wd, [Xn|SP, #soff]" , "op": "01111000|010|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsb Wd, [Xn|SP, #soff]" , "op": "00111000|100|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsb Xd, [Xn|SP, #soff]" , "op": "00111000|110|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsh Wd, [Xn|SP, #soff]" , "op": "01111000|100|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsh Xd, [Xn|SP, #soff]" , "op": "01111000|110|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsw Xd, [Xn|SP, #soff]" , "op": "10111000|100|soff:9|10|Rn|Rd"},
|
||||
{"inst": "ldur Wd, [Xn|SP, #soff]" , "op": "10111000|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldur Xd, [Xn|SP, #soff]" , "op": "11111000|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldurb Wd, [Xn|SP, #soff]" , "op": "00111000|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldurh Wd, [Xn|SP, #soff]" , "op": "01111000|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldursb Wd, [Xn|SP, #soff]" , "op": "00111000|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldursb Xd, [Xn|SP, #soff]" , "op": "00111000|110|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldursh Wd, [Xn|SP, #soff]" , "op": "01111000|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldursh Xd, [Xn|SP, #soff]" , "op": "01111000|110|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldursw Xd, [Xn|SP, #soff]" , "op": "10111000|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldxp Wd, Wd2, [Xn|SP, #soff*4]" , "op": "10001000|011|11111|0|Rd2|Rn|Rd"},
|
||||
{"inst": "ldxp Xd, Xd2, [Xn|SP, #soff*8]" , "op": "11001000|011|11111|0|Rd2|Rn|Rd"},
|
||||
{"inst": "ldtr Wd, [Xn|SP, #offS]" , "op": "10111000|010|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtr Xd, [Xn|SP, #offS]" , "op": "11111000|010|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrb Wd, [Xn|SP, #offS]" , "op": "00111000|010|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrh Wd, [Xn|SP, #offS]" , "op": "01111000|010|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsb Wd, [Xn|SP, #offS]" , "op": "00111000|100|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsb Xd, [Xn|SP, #offS]" , "op": "00111000|110|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsh Wd, [Xn|SP, #offS]" , "op": "01111000|100|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsh Xd, [Xn|SP, #offS]" , "op": "01111000|110|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldtrsw Xd, [Xn|SP, #offS]" , "op": "10111000|100|offS:9|10|Rn|Rd"},
|
||||
{"inst": "ldur Wd, [Xn|SP, #offS]" , "op": "10111000|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldur Xd, [Xn|SP, #offS]" , "op": "11111000|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldurb Wd, [Xn|SP, #offS]" , "op": "00111000|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldurh Wd, [Xn|SP, #offS]" , "op": "01111000|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldursb Wd, [Xn|SP, #offS]" , "op": "00111000|100|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldursb Xd, [Xn|SP, #offS]" , "op": "00111000|110|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldursh Wd, [Xn|SP, #offS]" , "op": "01111000|100|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldursh Xd, [Xn|SP, #offS]" , "op": "01111000|110|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldursw Xd, [Xn|SP, #offS]" , "op": "10111000|100|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldxp Wd, Wd2, [Xn|SP, #offS*4]" , "op": "10001000|011|11111|0|Rd2|Rn|Rd"},
|
||||
{"inst": "ldxp Xd, Xd2, [Xn|SP, #offS*8]" , "op": "11001000|011|11111|0|Rd2|Rn|Rd"},
|
||||
{"inst": "ldxr Wd, [Xn|SP]" , "op": "10001000|010|11111|0|11111|Rn|Rd"},
|
||||
{"inst": "ldxr Xd, [Xn|SP]" , "op": "11001000|010|11111|0|11111|Rn|Rd"},
|
||||
{"inst": "ldxrb Wd, [Xn|SP]" , "op": "00001000|010|11111|0|11111|Rn|Rd"},
|
||||
@@ -260,9 +260,9 @@
|
||||
{"inst": "orr Wd|WSP, Wn, #log_imm" , "op": "00110010|0|imm:13|Rn|Rd" , "imm": "ImmLogical(log_imm, 0)"},
|
||||
{"inst": "orr Xd|SP, Xn, #log_imm" , "op": "10110010|0|imm:13|Rn|Rd" , "imm": "ImmLogical(log_imm, 1)"},
|
||||
{"inst": "prfm #prf_op, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*8}]" , "op": "11111000|101|Rm|option:3|n:1|10|Rn|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfm #prf_op, [Xn|SP, #zoff]" , "op": "11111001|10|zoff:12|Rn|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfm #prf_op, [PC, #soff*4]" , "op": "11011000|soff:19|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfum #prf_op, [Xn|SP, #soff]" , "op": "11111000|100|soff:9|00|Rn|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfm #prf_op, [Xn|SP, #offZ]" , "op": "11111001|10|offZ:12|Rn|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfm #prf_op, [PC, #offS*4]" , "op": "11011000|offS:19|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "prfum #prf_op, [Xn|SP, #offS]" , "op": "11111000|100|offS:9|00|Rn|prf_op:5" , "imm": "ImmPRF(prf_op)"},
|
||||
{"inst": "pssbb" , "op": "11010101|000|00011|0011|0100|100|11111"},
|
||||
{"inst": "rbit Wd, Wn" , "op": "01011010|110|00000|0|00000|Rn|Rd"},
|
||||
{"inst": "rbit Xd, Xn" , "op": "11011010|110|00000|0|00000|Rn|Rd"},
|
||||
@@ -291,7 +291,7 @@
|
||||
{"inst": "sev" , "op": "11010101|000|00011|0010|0000|100|11111"},
|
||||
{"inst": "sevl" , "op": "11010101|000|00011|0010|0000|101|11111"},
|
||||
{"inst": "smaddl Xd, Wn, Wm, Xa" , "op": "10011011|001|Rm|0|Ra|Rn|Rd"},
|
||||
{"inst": "smc #zimm" , "op": "11010100|000|zimm:16|00011"},
|
||||
{"inst": "smc #immZ" , "op": "11010100|000|immZ:16|00011"},
|
||||
{"inst": "smnegl Xd, Wn, Wm" , "op": "10011011|001|Rm|1|11111|Rn|Rd"},
|
||||
{"inst": "smsubl Xd, Wn, Wm, Xa" , "op": "10011011|001|Rm|1|Ra|Rn|Rd"},
|
||||
{"inst": "smulh Xd, Xn, Xm" , "op": "10011011|010|Rm|0|11111|Rn|Rd"},
|
||||
@@ -307,34 +307,34 @@
|
||||
{"inst": "stlxr Wd, Xs, [Xn|SP]" , "op": "11001000|000|Rd|1|11111|Rn|Rs"},
|
||||
{"inst": "stlxrb Wd, Ws, [Xn|SP]" , "op": "00001000|000|Rd|1|11111|Rn|Rs"},
|
||||
{"inst": "stlxrh Wd, Xs, [Xn|SP]" , "op": "01001000|000|Rd|1|11111|Rn|Rs"},
|
||||
{"inst": "stnp Ws, Ws2, [Xn|SP, #simm*4]" , "op": "00101000|00|simm:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stnp Xs, Xs2, [Xn|SP, #simm*8]" , "op": "10101000|00|simm:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stp Ws, Ws2, [Xn|SP, #simm*4]{@}{!}" , "op": "0010100|!post|W|0|simm:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stp Xs, Xs2, [Xn|SP, #simm*8]{@}{!}" , "op": "1010100|!post|W|0|simm:7|Rs2|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #zoff*4]" , "op": "10111001|00|zoff:12|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #zoff*8]" , "op": "11111001|00|zoff:12|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #soff*4]@" , "op": "10111000|000|soff:9|01|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #soff*8]@" , "op": "11111000|000|soff:9|01|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #soff*4]!" , "op": "10111000|000|soff:9|11|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #soff*8]!" , "op": "11111000|000|soff:9|11|Rn|Rs"},
|
||||
{"inst": "stnp Ws, Ws2, [Xn|SP, #offS*4]" , "op": "00101000|00|offS:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stnp Xs, Xs2, [Xn|SP, #offS*8]" , "op": "10101000|00|offS:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stp Ws, Ws2, [Xn|SP, #offS*4]{@}{!}" , "op": "0010100|!post|W|0|offS:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stp Xs, Xs2, [Xn|SP, #offS*8]{@}{!}" , "op": "1010100|!post|W|0|offS:7|Rs2|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #offZ*4]" , "op": "10111001|00|offZ:12|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #offZ*8]" , "op": "11111001|00|offZ:12|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #offS*4]@" , "op": "10111000|000|offS:9|01|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #offS*8]@" , "op": "11111000|000|offS:9|01|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, #offS*4]!" , "op": "10111000|000|offS:9|11|Rn|Rs"},
|
||||
{"inst": "str Xs, [Xn|SP, #offS*8]!" , "op": "11111000|000|offS:9|11|Rn|Rs"},
|
||||
{"inst": "str Ws, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "10111000|001|Rm|option:3|s:1|10|Rn|Rs" , "imm": "ImmLDR_STR(iop, n)"},
|
||||
{"inst": "str Xs, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "11111000|001|Rm|option:3|s:1|10|Rn|Rs" , "imm": "ImmLDR_STR(iop, n)"},
|
||||
{"inst": "strb Ws, [Xn|SP, #zoff]" , "op": "00111001|00|zoff:12|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, #soff]@" , "op": "00111000|000|soff:9|01|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, #soff]!" , "op": "00111000|000|soff:9|11|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, #offZ]" , "op": "00111001|00|offZ:12|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, #offS]@" , "op": "00111000|000|offS:9|01|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, #offS]!" , "op": "00111000|000|offS:9|11|Rn|Rs"},
|
||||
{"inst": "strb Ws, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111000|001|Rm|option:3|s:1|10|Rn|Rs" , "imm": "ImmLDRB_STRB(iop, n)"},
|
||||
{"inst": "strh Ws, [Xn|SP, #zoff*2]" , "op": "01111001|00|zoff:12|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, #soff*2]@" , "op": "01111000|000|soff:9|01|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, #soff*2]!" , "op": "01111000|000|soff:9|11|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, #offZ*2]" , "op": "01111001|00|offZ:12|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, #offS*2]@" , "op": "01111000|000|offS:9|01|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, #offS*2]!" , "op": "01111000|000|offS:9|11|Rn|Rs"},
|
||||
{"inst": "strh Ws, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111000|001|Rm|option:3|s:1|10|Rn|Rs" , "imm": "ImmLDRH_STRH(iop, n)"},
|
||||
{"inst": "sttr Ws, [Xn|SP, #soff]" , "op": "10111000|000|soff:9|10|Rn|Rs"},
|
||||
{"inst": "sttr Xs, [Xn|SP, #soff]" , "op": "11111000|000|soff:9|10|Rn|Rs"},
|
||||
{"inst": "sttrb Ws, [Xn|SP, #soff]" , "op": "00111000|000|soff:9|10|Rn|Rs"},
|
||||
{"inst": "sttrh Ws, [Xn|SP, #soff]" , "op": "01111000|000|soff:9|10|Rn|Rs"},
|
||||
{"inst": "stur Ws, [Xn|SP, #soff]" , "op": "10111000|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "stur Xs, [Xn|SP, #soff]" , "op": "11111000|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "sturb Ws, [Xn|SP, #soff]" , "op": "00111000|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "sturh Ws, [Xn|SP, #soff]" , "op": "01111000|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "sttr Ws, [Xn|SP, #offS]" , "op": "10111000|000|offS:9|10|Rn|Rs"},
|
||||
{"inst": "sttr Xs, [Xn|SP, #offS]" , "op": "11111000|000|offS:9|10|Rn|Rs"},
|
||||
{"inst": "sttrb Ws, [Xn|SP, #offS]" , "op": "00111000|000|offS:9|10|Rn|Rs"},
|
||||
{"inst": "sttrh Ws, [Xn|SP, #offS]" , "op": "01111000|000|offS:9|10|Rn|Rs"},
|
||||
{"inst": "stur Ws, [Xn|SP, #offS]" , "op": "10111000|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "stur Xs, [Xn|SP, #offS]" , "op": "11111000|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "sturb Ws, [Xn|SP, #offS]" , "op": "00111000|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "sturh Ws, [Xn|SP, #offS]" , "op": "01111000|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "stxp Wd, Ws, Ws2, [Xn|SP]" , "op": "10001000|001|Rd|0|Rs2|Rn|Rs"},
|
||||
{"inst": "stxp Wd, Xs, Xs2, [Xn|SP]" , "op": "11001000|001|Rd|0|Rs2|Rn|Rs"},
|
||||
{"inst": "stxr Wd, Ws, [Xn|SP]" , "op": "10001000|000|Rd|0|11111|Rn|Rs"},
|
||||
@@ -353,7 +353,7 @@
|
||||
{"inst": "subs Xd, Xn|SP, Rm, {extend #n}" , "op": "11101011|00|1|Rm|option:3|n:3|Rn|Rd" , "io": "N=W Z=W C=W V=W"},
|
||||
{"inst": "subs Wd|WSP, Wn|WSP, #immZ, {lsl #n=0|12}" , "op": "01110001|0|n:1|immZ:12|Rn|Rd" , "io": "N=W Z=W C=W V=W"},
|
||||
{"inst": "subs Xd|SP, Xn|SP, #immZ, {lsl #n=0|12}" , "op": "11110001|0|n:1|immZ:12|Rn|Rd" , "io": "N=W Z=W C=W V=W"},
|
||||
{"inst": "svc #zimm" , "op": "11010100|000|zimm:16|00001"},
|
||||
{"inst": "svc #immZ" , "op": "11010100|000|immZ:16|00001"},
|
||||
{"inst": "sxtb Wd, Wn" , "op": "00010011|000|00000|0|00111|Rn|Rd"},
|
||||
{"inst": "sxtb Xd, Wn" , "op": "10010011|010|00000|0|00111|Rn|Rd"},
|
||||
{"inst": "sxth Wd, Wn" , "op": "00010011|000|00000|0|01111|Rn|Rd"},
|
||||
@@ -431,20 +431,20 @@
|
||||
{"inst": "ctz Xd, Xn" , "op": "11011010|110|00000|0|00110|Rn|Rd"},
|
||||
{"inst": "smax Wd, Wn, Wm" , "op": "00011010|110|Rm|0|11000|Rn|Rd"},
|
||||
{"inst": "smax Xd, Xn, Xm" , "op": "10011010|110|Rm|0|11000|Rn|Rd"},
|
||||
{"inst": "smax Wd, Wn, #simm" , "op": "00010001|110|000|simm:8|Rn|Rd"},
|
||||
{"inst": "smax Xd, Xn, #simm" , "op": "10010001|110|000|simm:8|Rn|Rd"},
|
||||
{"inst": "smax Wd, Wn, #immS" , "op": "00010001|110|000|immS:8|Rn|Rd"},
|
||||
{"inst": "smax Xd, Xn, #immS" , "op": "10010001|110|000|immS:8|Rn|Rd"},
|
||||
{"inst": "smin Wd, Wn, Wm" , "op": "00011010|110|Rm|0|11010|Rn|Rd"},
|
||||
{"inst": "smin Xd, Xn, Xm" , "op": "10011010|110|Rm|0|11010|Rn|Rd"},
|
||||
{"inst": "smin Wd, Wn, #simm" , "op": "00010001|110|010|simm:8|Rn|Rd"},
|
||||
{"inst": "smin Xd, Xn, #simm" , "op": "10010001|110|010|simm:8|Rn|Rd"},
|
||||
{"inst": "smin Wd, Wn, #immS" , "op": "00010001|110|010|immS:8|Rn|Rd"},
|
||||
{"inst": "smin Xd, Xn, #immS" , "op": "10010001|110|010|immS:8|Rn|Rd"},
|
||||
{"inst": "umax Wd, Wn, Wm" , "op": "00011010|110|Rm|0|11001|Rn|Rd"},
|
||||
{"inst": "umax Xd, Xn, Xm" , "op": "10011010|110|Rm|0|11001|Rn|Rd"},
|
||||
{"inst": "umax Wd, Wn, #simm" , "op": "00010001|110|001|simm:8|Rn|Rd"},
|
||||
{"inst": "umax Xd, Xn, #simm" , "op": "10010001|110|001|simm:8|Rn|Rd"},
|
||||
{"inst": "umax Wd, Wn, #immZ" , "op": "00010001|110|001|immZ:8|Rn|Rd"},
|
||||
{"inst": "umax Xd, Xn, #immZ" , "op": "10010001|110|001|immZ:8|Rn|Rd"},
|
||||
{"inst": "umin Wd, Wn, Wm" , "op": "00011010|110|Rm|0|11011|Rn|Rd"},
|
||||
{"inst": "umin Xd, Xn, Xm" , "op": "10011010|110|Rm|0|11011|Rn|Rd"},
|
||||
{"inst": "umin Wd, Wn, #simm" , "op": "00010001|110|011|simm:8|Rn|Rd"},
|
||||
{"inst": "umin Xd, Xn, #simm" , "op": "10010001|110|011|simm:8|Rn|Rd"}
|
||||
{"inst": "umin Wd, Wn, #immZ" , "op": "00010001|110|011|immZ:8|Rn|Rd"},
|
||||
{"inst": "umin Xd, Xn, #immZ" , "op": "10010001|110|011|immZ:8|Rn|Rd"}
|
||||
]},
|
||||
|
||||
{"category": "GP GP_EXT", "ext": "D128", "data": [
|
||||
@@ -510,21 +510,21 @@
|
||||
]},
|
||||
|
||||
{"category": "GP GP_EXT", "ext": "LRCPC2", "data": [
|
||||
{"inst": "ldapur Wd, [Xn|SP, #soff]" , "op": "10011001|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapur Xd, [Xn|SP, #soff]" , "op": "11011001|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapurb Wd, [Xn|SP, #soff]" , "op": "00011001|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapurh Wd, [Xn|SP, #soff]" , "op": "01011001|010|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapur Wd, [Xn|SP, #offS]" , "op": "10011001|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapur Xd, [Xn|SP, #offS]" , "op": "11011001|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapurb Wd, [Xn|SP, #offS]" , "op": "00011001|010|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapurh Wd, [Xn|SP, #offS]" , "op": "01011001|010|offS:9|00|Rn|Rd"},
|
||||
|
||||
{"inst": "ldapursb Wd, [Xn|SP, #soff]" , "op": "00011001|110|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursb Xd, [Xn|SP, #soff]" , "op": "00011001|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursh Wd, [Xn|SP, #soff]" , "op": "01011001|110|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursh Xd, [Xn|SP, #soff]" , "op": "01011001|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursw Xd, [Xn|SP, #soff]" , "op": "10011001|100|soff:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursb Wd, [Xn|SP, #offS]" , "op": "00011001|110|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursb Xd, [Xn|SP, #offS]" , "op": "00011001|100|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursh Wd, [Xn|SP, #offS]" , "op": "01011001|110|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursh Xd, [Xn|SP, #offS]" , "op": "01011001|100|offS:9|00|Rn|Rd"},
|
||||
{"inst": "ldapursw Xd, [Xn|SP, #offS]" , "op": "10011001|100|offS:9|00|Rn|Rd"},
|
||||
|
||||
{"inst": "stlur Ws, [Xn|SP, #soff]" , "op": "10011001|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "stlur Xs, [Xn|SP, #soff]" , "op": "11011001|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "stlurb Ws, [Xn|SP, #soff]" , "op": "00011001|000|soff:9|00|Rn|Rs"},
|
||||
{"inst": "stlurh Ws, [Xn|SP, #soff]" , "op": "01011001|000|soff:9|00|Rn|Rs"}
|
||||
{"inst": "stlur Ws, [Xn|SP, #offS]" , "op": "10011001|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "stlur Xs, [Xn|SP, #offS]" , "op": "11011001|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "stlurb Ws, [Xn|SP, #offS]" , "op": "00011001|000|offS:9|00|Rn|Rs"},
|
||||
{"inst": "stlurh Ws, [Xn|SP, #offS]" , "op": "01011001|000|offS:9|00|Rn|Rs"}
|
||||
]},
|
||||
|
||||
{"category": "GP GP_EXT", "ext": "LRCPC3", "data": [
|
||||
@@ -981,12 +981,12 @@
|
||||
{"inst": "cmpp Xn|SP, Xm|SP" , "op": "10111010|110|Rm|000000|Rn|11111"},
|
||||
{"inst": "gmi Xd, Xn|SP, Xm" , "op": "10011010|110|Rm|000101|Rn|Rd"},
|
||||
{"inst": "irg Xd, Xn|SP, Xm" , "op": "10011010|110|Rm|000100|Rn|Rd"},
|
||||
{"inst": "ldg Xd, [Xn|SP, #soff*16]" , "op": "11011001|011|soff:9|00|Rn|Rd"},
|
||||
{"inst": "st2g Xs|SP, [Xn|SP, #soff*16]{@}{!}" , "op": "11011001|101|soff:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stg Xs|SP, [Xn|SP, #soff*16]{@}{!}" , "op": "11011001|001|soff:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stgp Xs, Xs2, [Xn|SP, #soff*16]{@}{!}" , "op": "0110100|!post|W|0|soff:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stz2g Xs|SP, [Xn|SP, #soff*16]{@}{!}" , "op": "11011001|111|soff:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stzg Xs|SP, [Xn|SP, #soff*16]{@}{!}" , "op": "11011001|011|soff:9|!post|W|Rn|Rs"},
|
||||
{"inst": "ldg Xd, [Xn|SP, #offS*16]" , "op": "11011001|011|offS:9|00|Rn|Rd"},
|
||||
{"inst": "st2g Xs|SP, [Xn|SP, #offS*16]{@}{!}" , "op": "11011001|101|offS:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stg Xs|SP, [Xn|SP, #offS*16]{@}{!}" , "op": "11011001|001|offS:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stgp Xs, Xs2, [Xn|SP, #offS*16]{@}{!}" , "op": "0110100|!post|W|0|offS:7|Rs2|Rn|Rs"},
|
||||
{"inst": "stz2g Xs|SP, [Xn|SP, #offS*16]{@}{!}" , "op": "11011001|111|offS:9|!post|W|Rn|Rs"},
|
||||
{"inst": "stzg Xs|SP, [Xn|SP, #offS*16]{@}{!}" , "op": "11011001|011|offS:9|!post|W|Rn|Rs"},
|
||||
{"inst": "subg Xd|SP, Xn|SP, #imm1, #imm2" , "op": "11010001|10|imm1:6|00|imm2:4|Rn|Rd"},
|
||||
{"inst": "subp Xd, Xn|SP, Xm|SP" , "op": "10011010|110|Rm|0|00000|Rn|Rd"},
|
||||
{"inst": "subps Xd, Xn|SP, Xm|SP" , "op": "10011010|110|Rm|0|00000|Rn|Rd" , "io": "N=W Z=W C=W V=W"}
|
||||
@@ -1023,8 +1023,8 @@
|
||||
{"inst": "brabz Xn" , "op": "11010110|000|11111|0000|11|Rn|11111" , "control": "call"},
|
||||
{"inst": "eretaa" , "op": "11010110|100|11111|0000|10|11111|11111" , "control": "return"},
|
||||
{"inst": "eretab" , "op": "11010110|100|11111|0000|11|11111|11111" , "control": "return"},
|
||||
{"inst": "ldraa Xd, [Xn|SP, #soff]{!}" , "op": "11111000|0|soff:1|1|soff:9|W1|Rn|Rd"},
|
||||
{"inst": "ldrab Xd, [Xn|SP, #soff]{!}" , "op": "11111000|1|soff:1|1|soff:9|W1|Rn|Rd"},
|
||||
{"inst": "ldraa Xd, [Xn|SP, #offS]{!}" , "op": "11111000|0|offS:1|1|offS:9|W1|Rn|Rd"},
|
||||
{"inst": "ldrab Xd, [Xn|SP, #offS]{!}" , "op": "11111000|1|offS:1|1|offS:9|W1|Rn|Rd"},
|
||||
{"inst": "pacda Xd, Xn|SP" , "op": "11011010|110|00001|0|00010|Rn|Rd"},
|
||||
{"inst": "pacdb Xd, Xn|SP" , "op": "11011010|110|00001|0|00011|Rn|Rd"},
|
||||
{"inst": "pacdza Xd" , "op": "11011010|110|00001|0|01010|11111|Rd"},
|
||||
@@ -1768,40 +1768,40 @@
|
||||
{"inst": "ld4r 4x{Vd.t}, [Xn|SP, Xm]@" , "op": "01001101|111|Rm |1110|sz|Rn|Vd" , "t": "16B 8H 4S 2D"},
|
||||
{"inst": "ld4r 4x{Vd.t}, [Xn|SP, #off==4<<sz]@" , "op": "00001101|111|11111|1110|sz|Rn|Vd" , "t": "8B 4H 2S 1D"},
|
||||
{"inst": "ld4r 4x{Vd.t}, [Xn|SP, #off==4<<sz]@" , "op": "01001101|111|11111|1110|sz|Rn|Vd" , "t": "16B 8H 4S 2D"},
|
||||
{"inst": "ldnp Sd, Sd2, [Xn|SP, #soff*4]" , "op": "00101100|01|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldnp Dd, Dd2, [Xn|SP, #soff*8]" , "op": "01101100|01|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldnp Qd, Qd2, [Xn|SP, #soff*16]" , "op": "10101100|01|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Sd, Sd2, [Xn|SP, #soff*4]{@}{!}" , "op": "0010110|!post|W|1|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Dd, Dd2, [Xn|SP, #soff*8]{@}{!}" , "op": "0110110|!post|W|1|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Qd, Qd2, [Xn|SP, #soff*16]{@}{!}" , "op": "1010110|!post|W|1|soff:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldnp Sd, Sd2, [Xn|SP, #offS*4]" , "op": "00101100|01|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldnp Dd, Dd2, [Xn|SP, #offS*8]" , "op": "01101100|01|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldnp Qd, Qd2, [Xn|SP, #offS*16]" , "op": "10101100|01|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Sd, Sd2, [Xn|SP, #offS*4]{@}{!}" , "op": "0010110|!post|W|1|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Dd, Dd2, [Xn|SP, #offS*8]{@}{!}" , "op": "0110110|!post|W|1|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldp Qd, Qd2, [Xn|SP, #offS*16]{@}{!}" , "op": "1010110|!post|W|1|offS:7|Vd2|Vn|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111100|011|Rm|option:3|n:1|10|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111100|011|Rm|option:3|n:1|10|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*2}]" , "op": "10111100|011|Rm|option:3|n:1|10|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*3}]" , "op": "11111100|011|Rm|option:3|n:1|10|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*4}]" , "op": "00111100|111|Rm|option:3|n:1|10|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [PC, #soff*4]" , "op": "00011100|soff:19|Vd"},
|
||||
{"inst": "ldr Dd, [PC, #soff*4]" , "op": "01011100|soff:19|Vd"},
|
||||
{"inst": "ldr Qd, [PC, #soff*4]" , "op": "10011100|soff:19|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #zoff]" , "op": "00111101|01|zoff:12|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #zoff*2]" , "op": "01111101|01|zoff:12|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #zoff*4]" , "op": "10111101|01|zoff:12|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #zoff*8]" , "op": "11111101|01|zoff:12|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #zoff*16]" , "op": "00111101|11|zoff:12|Rn|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #soff]!" , "op": "00111100|010|soff:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #soff*2]!" , "op": "01111100|010|soff:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #soff*4]!" , "op": "10111100|010|soff:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #soff*8]!" , "op": "11111100|010|soff:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #soff*16]!" , "op": "00111100|110|soff:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #soff]@" , "op": "00111100|010|soff:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #soff*2]@" , "op": "01111100|010|soff:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #soff*4]@" , "op": "10111100|010|soff:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #soff*8]@" , "op": "11111100|010|soff:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #soff*16]@" , "op": "00111100|110|soff:9|01|Rn|Vd"},
|
||||
{"inst": "ldur Bd, [Xn|SP, #soff]" , "op": "00111100|010|soff:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Hd, [Xn|SP, #soff]" , "op": "01111100|010|soff:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Sd, [Xn|SP, #soff]" , "op": "10111100|010|soff:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Dd, [Xn|SP, #soff]" , "op": "11111100|010|soff:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Qd, [Xn|SP, #soff]" , "op": "00111100|110|soff:9|00|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [PC, #offS*4]" , "op": "00011100|offS:19|Vd"},
|
||||
{"inst": "ldr Dd, [PC, #offS*4]" , "op": "01011100|offS:19|Vd"},
|
||||
{"inst": "ldr Qd, [PC, #offS*4]" , "op": "10011100|offS:19|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #offZ]" , "op": "00111101|01|offZ:12|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #offZ*2]" , "op": "01111101|01|offZ:12|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #offZ*4]" , "op": "10111101|01|offZ:12|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #offZ*8]" , "op": "11111101|01|offZ:12|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #offZ*16]" , "op": "00111101|11|offZ:12|Rn|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #offS]!" , "op": "00111100|010|offS:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #offS*2]!" , "op": "01111100|010|offS:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #offS*4]!" , "op": "10111100|010|offS:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #offS*8]!" , "op": "11111100|010|offS:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #offS*16]!" , "op": "00111100|110|offS:9|11|Rn|Vd"},
|
||||
{"inst": "ldr Bd, [Xn|SP, #offS]@" , "op": "00111100|010|offS:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Hd, [Xn|SP, #offS*2]@" , "op": "01111100|010|offS:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Sd, [Xn|SP, #offS*4]@" , "op": "10111100|010|offS:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Dd, [Xn|SP, #offS*8]@" , "op": "11111100|010|offS:9|01|Rn|Vd"},
|
||||
{"inst": "ldr Qd, [Xn|SP, #offS*16]@" , "op": "00111100|110|offS:9|01|Rn|Vd"},
|
||||
{"inst": "ldur Bd, [Xn|SP, #offS]" , "op": "00111100|010|offS:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Hd, [Xn|SP, #offS]" , "op": "01111100|010|offS:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Sd, [Xn|SP, #offS]" , "op": "10111100|010|offS:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Dd, [Xn|SP, #offS]" , "op": "11111100|010|offS:9|00|Rn|Vd"},
|
||||
{"inst": "ldur Qd, [Xn|SP, #offS]" , "op": "00111100|110|offS:9|00|Rn|Vd"},
|
||||
{"inst": "mla Vx.t, Vn.t, Vm.t" , "op": "00001110|sz|1|Vm|10010|1|Vn|Vx" , "t": "8B 4H 2S"},
|
||||
{"inst": "mla Vx.t, Vn.t, Vm.t" , "op": "01001110|sz|1|Vm|10010|1|Vn|Vx" , "t": "16B 8H 4S"},
|
||||
{"inst": "mla Vx.4H, Vn.4H, Vm.H[#idx]" , "op": "00101111|01|idx[1:0]|Vm:4|0000|idx[2]|0|Vn|Vx"},
|
||||
@@ -1934,18 +1934,18 @@
|
||||
{"inst": "sminv Hd, Vn.4H" , "op": "00001110|01|11000|11010|10|Vn|Vd"},
|
||||
{"inst": "sminv Hd, Vn.8H" , "op": "01001110|01|11000|11010|10|Vn|Vd"},
|
||||
{"inst": "sminv Sd, Vn.4S" , "op": "01001110|10|11000|11010|10|Vn|Vd"},
|
||||
{"inst": "smlal Vd.ta, Vn.tb, Vm.tb" , "op": "00001110|sz|1|Vm|10000|0|Vn|Vd" , "t": "8H.8B 4S.4H 2D.2S"},
|
||||
{"inst": "smlal2 Vd.ta, Vn.tb, Vm.tb" , "op": "01001110|sz|1|Vm|10000|0|Vn|Vd" , "t": "8H.16B 4S.8H 2D.4S"},
|
||||
{"inst": "smlal Vd.4S, Vn.4H, Vm.H[#dx]" , "op": "00001111|01|idx[1:0]|Vm:4|0010|idx[2]|0|Vn|Vd"},
|
||||
{"inst": "smlal2 Vd.4S, Vn.8H, Vm.H[#dx]" , "op": "01001111|01|idx[1:0]|Vm:4|0010|idx[2]|0|Vn|Vd"},
|
||||
{"inst": "smlal Vd.2D, Vn.2S, Vm.S[#dx]" , "op": "00001111|10|idx[0] |Vm |0010|idx[1]|0|Vn|Vd"},
|
||||
{"inst": "smlal2 Vd.2D, Vn.4S, Vm.S[#dx]" , "op": "01001111|10|idx[0] |Vm |0010|idx[1]|0|Vn|Vd"},
|
||||
{"inst": "smlsl Vd.ta, Vn.tb, Vm.tb" , "op": "00001110|sz|1|Vm|10100|0|Vn|Vd" , "t": "8H.8B 4S.4H 2D.2S"},
|
||||
{"inst": "smlsl2 Vd.ta, Vn.tb, Vm.tb" , "op": "01001110|sz|1|Vm|10100|0|Vn|Vd" , "t": "8H.16B 4S.8H 2D.4S"},
|
||||
{"inst": "smlsl Vd.4S, Vn.4H, Vm.H[#dx]" , "op": "00001111|01|idx[1:0]|Vm:4|0110|idx[2]|0|Vn|Vd"},
|
||||
{"inst": "smlsl2 Vd.4S, Vn.8H, Vm.H[#dx]" , "op": "01001111|01|idx[1:0]|Vm:4|0110|idx[2]|0|Vn|Vd"},
|
||||
{"inst": "smlsl Vd.2D, Vn.2S, Vm.S[#dx]" , "op": "00001111|10|idx[0] |Vm |0110|idx[1]|0|Vn|Vd"},
|
||||
{"inst": "smlsl2 Vd.2D, Vn.4S, Vm.S[#dx]" , "op": "01001111|10|idx[0] |Vm |0110|idx[1]|0|Vn|Vd"},
|
||||
{"inst": "smlal Vx.ta, Vn.tb, Vm.tb" , "op": "00001110|sz|1|Vm|10000|0|Vn|Vx" , "t": "8H.8B 4S.4H 2D.2S"},
|
||||
{"inst": "smlal2 Vx.ta, Vn.tb, Vm.tb" , "op": "01001110|sz|1|Vm|10000|0|Vn|Vx" , "t": "8H.16B 4S.8H 2D.4S"},
|
||||
{"inst": "smlal Vx.4S, Vn.4H, Vm.H[#dx]" , "op": "00001111|01|idx[1:0]|Vm:4|0010|idx[2]|0|Vn|Vx"},
|
||||
{"inst": "smlal2 Vx.4S, Vn.8H, Vm.H[#dx]" , "op": "01001111|01|idx[1:0]|Vm:4|0010|idx[2]|0|Vn|Vx"},
|
||||
{"inst": "smlal Vx.2D, Vn.2S, Vm.S[#dx]" , "op": "00001111|10|idx[0] |Vm |0010|idx[1]|0|Vn|Vx"},
|
||||
{"inst": "smlal2 Vx.2D, Vn.4S, Vm.S[#dx]" , "op": "01001111|10|idx[0] |Vm |0010|idx[1]|0|Vn|Vx"},
|
||||
{"inst": "smlsl Vx.ta, Vn.tb, Vm.tb" , "op": "00001110|sz|1|Vm|10100|0|Vn|Vx" , "t": "8H.8B 4S.4H 2D.2S"},
|
||||
{"inst": "smlsl2 Vx.ta, Vn.tb, Vm.tb" , "op": "01001110|sz|1|Vm|10100|0|Vn|Vx" , "t": "8H.16B 4S.8H 2D.4S"},
|
||||
{"inst": "smlsl Vx.4S, Vn.4H, Vm.H[#dx]" , "op": "00001111|01|idx[1:0]|Vm:4|0110|idx[2]|0|Vn|Vx"},
|
||||
{"inst": "smlsl2 Vx.4S, Vn.8H, Vm.H[#dx]" , "op": "01001111|01|idx[1:0]|Vm:4|0110|idx[2]|0|Vn|Vx"},
|
||||
{"inst": "smlsl Vx.2D, Vn.2S, Vm.S[#dx]" , "op": "00001111|10|idx[0] |Vm |0110|idx[1]|0|Vn|Vx"},
|
||||
{"inst": "smlsl2 Vx.2D, Vn.4S, Vm.S[#dx]" , "op": "01001111|10|idx[0] |Vm |0110|idx[1]|0|Vn|Vx"},
|
||||
{"inst": "smov Wd, Vn.B[#idx]" , "op": "00001110|00|0|idx:4| 1|00101|1|Vn|Rd"},
|
||||
{"inst": "smov Wd, Vn.H[#idx]" , "op": "00001110|00|0|idx:3| 10|00101|1|Vn|Rd"},
|
||||
{"inst": "smov Xd, Vn.B[#idx]" , "op": "01001110|00|0|idx:4| 1|00101|1|Vn|Rd"},
|
||||
@@ -2216,37 +2216,37 @@
|
||||
{"inst": "st4 4x{Vs.t}+, [Xn|SP, Xm]@" , "op": "01001100|100|Rm |0000|sz|Rn|Vs" , "t": "16B 8H 4S 2D"},
|
||||
{"inst": "st4 4x{Vs.t}+, [Xn|SP, #off==32]@" , "op": "00001100|100|11111|0000|sz|Rn|Vs" , "t": "8B 4H 2S"},
|
||||
{"inst": "st4 4x{Vs.t}+, [Xn|SP, #off==64]@" , "op": "01001100|100|11111|0000|sz|Rn|Vs" , "t": "16B 8H 4S 2D"},
|
||||
{"inst": "stnp Sd, Sd2, [Xn|SP, #soff*4]" , "op": "00101100|00|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stnp Dd, Dd2, [Xn|SP, #soff*8]" , "op": "01101100|00|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stnp Qd, Qd2, [Xn|SP, #soff*16]" , "op": "10101100|00|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Sd, Sd2, [Xn|SP, #soff*4]{@}{!}" , "op": "0010110|!post|W|0|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Dd, Dd2, [Xn|SP, #soff*8]{@}{!}" , "op": "0110110|!post|W|0|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Qd, Qd2, [Xn|SP, #soff*16]{@}{!}" , "op": "1010110|!post|W|0|soff:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stnp Sd, Sd2, [Xn|SP, #offS*4]" , "op": "00101100|00|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stnp Dd, Dd2, [Xn|SP, #offS*8]" , "op": "01101100|00|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stnp Qd, Qd2, [Xn|SP, #offS*16]" , "op": "10101100|00|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Sd, Sd2, [Xn|SP, #offS*4]{@}{!}" , "op": "0010110|!post|W|0|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Dd, Dd2, [Xn|SP, #offS*8]{@}{!}" , "op": "0110110|!post|W|0|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "stp Qd, Qd2, [Xn|SP, #offS*16]{@}{!}" , "op": "1010110|!post|W|0|offS:7|Vs2|Vn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "00111100|001|Rm|option:3|n:1|10|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n}]" , "op": "01111100|001|Rm|option:3|n:1|10|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*2}]" , "op": "10111100|001|Rm|option:3|n:1|10|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*3}]" , "op": "11111100|001|Rm|option:3|n:1|10|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, Rm, {uxtw|lsl|sxtw|sxtx #n*4}]" , "op": "00111100|101|Rm|option:3|n:1|10|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #zoff]" , "op": "00111101|00|zoff:12|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #zoff*2]" , "op": "01111101|00|zoff:12|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #zoff*4]" , "op": "10111101|00|zoff:12|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #zoff*8]" , "op": "11111101|00|zoff:12|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #zoff*16]" , "op": "00111101|10|zoff:12|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #soff]!" , "op": "00111100|000|soff:9|11|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #soff*2]!" , "op": "01111100|000|soff:9|11|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #soff*4]!" , "op": "10111100|000|soff:9|11|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #soff*8]!" , "op": "11111100|000|soff:9|11|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #soff*16]!" , "op": "00111100|100|soff:9|11|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #soff]@" , "op": "00111100|000|soff:9|01|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #soff*2]@" , "op": "01111100|000|soff:9|01|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #soff*4]@" , "op": "10111100|000|soff:9|01|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #soff*8]@" , "op": "11111100|000|soff:9|01|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #soff*16]@" , "op": "00111100|100|soff:9|01|Rn|Vs"},
|
||||
{"inst": "stur Bd, [Xn|SP, #soff]" , "op": "00111100|000|soff:9|00|Rn|Vs"},
|
||||
{"inst": "stur Hd, [Xn|SP, #soff]" , "op": "01111100|000|soff:9|00|Rn|Vs"},
|
||||
{"inst": "stur Sd, [Xn|SP, #soff]" , "op": "10111100|000|soff:9|00|Rn|Vs"},
|
||||
{"inst": "stur Dd, [Xn|SP, #soff]" , "op": "11111100|000|soff:9|00|Rn|Vs"},
|
||||
{"inst": "stur Qd, [Xn|SP, #soff]" , "op": "00111100|100|soff:9|00|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #offZ]" , "op": "00111101|00|offZ:12|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #offZ*2]" , "op": "01111101|00|offZ:12|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #offZ*4]" , "op": "10111101|00|offZ:12|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #offZ*8]" , "op": "11111101|00|offZ:12|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #offZ*16]" , "op": "00111101|10|offZ:12|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #offS]!" , "op": "00111100|000|offS:9|11|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #offS*2]!" , "op": "01111100|000|offS:9|11|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #offS*4]!" , "op": "10111100|000|offS:9|11|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #offS*8]!" , "op": "11111100|000|offS:9|11|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #offS*16]!" , "op": "00111100|100|offS:9|11|Rn|Vs"},
|
||||
{"inst": "str Bd, [Xn|SP, #offS]@" , "op": "00111100|000|offS:9|01|Rn|Vs"},
|
||||
{"inst": "str Hd, [Xn|SP, #offS*2]@" , "op": "01111100|000|offS:9|01|Rn|Vs"},
|
||||
{"inst": "str Sd, [Xn|SP, #offS*4]@" , "op": "10111100|000|offS:9|01|Rn|Vs"},
|
||||
{"inst": "str Dd, [Xn|SP, #offS*8]@" , "op": "11111100|000|offS:9|01|Rn|Vs"},
|
||||
{"inst": "str Qd, [Xn|SP, #offS*16]@" , "op": "00111100|100|offS:9|01|Rn|Vs"},
|
||||
{"inst": "stur Bd, [Xn|SP, #offS]" , "op": "00111100|000|offS:9|00|Rn|Vs"},
|
||||
{"inst": "stur Hd, [Xn|SP, #offS]" , "op": "01111100|000|offS:9|00|Rn|Vs"},
|
||||
{"inst": "stur Sd, [Xn|SP, #offS]" , "op": "10111100|000|offS:9|00|Rn|Vs"},
|
||||
{"inst": "stur Dd, [Xn|SP, #offS]" , "op": "11111100|000|offS:9|00|Rn|Vs"},
|
||||
{"inst": "stur Qd, [Xn|SP, #offS]" , "op": "00111100|100|offS:9|00|Rn|Vs"},
|
||||
{"inst": "sub Dd, Dn, Dm" , "op": "01111110|11|1|Vm|10000|1|Vn|Vd"},
|
||||
{"inst": "sub Vd.t, Vn.t, Vm.t" , "op": "00101110|sz|1|Vm|10000|1|Vn|Vd" , "t": "8B 4H 2S"},
|
||||
{"inst": "sub Vd.t, Vn.t, Vm.t" , "op": "01101110|sz|1|Vm|10000|1|Vn|Vd" , "t": "16B 8H 4S 2D"},
|
||||
@@ -2810,17 +2810,17 @@
|
||||
|
||||
{"category": "ASIMD", "ext": "ASIMD LRCPC3", "data": [
|
||||
{"inst": "ldap1 Vd.D[#idx], [Xn|SP]" , "op": "0|idx:1|001101|010|00001|10000|1|Rn|Vd"},
|
||||
{"inst": "ldapur Bd, [Xn|SP, #soff]" , "op": "00011101|010|soff:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Hd, [Xn|SP, #soff]" , "op": "01011101|010|soff:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Sd, [Xn|SP, #soff]" , "op": "10011101|010|soff:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Dd, [Xn|SP, #soff]" , "op": "11011101|010|soff:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Qd, [Xn|SP, #soff]" , "op": "00011101|110|soff:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Bd, [Xn|SP, #offS]" , "op": "00011101|010|offS:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Hd, [Xn|SP, #offS]" , "op": "01011101|010|offS:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Sd, [Xn|SP, #offS]" , "op": "10011101|010|offS:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Dd, [Xn|SP, #offS]" , "op": "11011101|010|offS:9|10|Rn|Vd"},
|
||||
{"inst": "ldapur Qd, [Xn|SP, #offS]" , "op": "00011101|110|offS:9|10|Rn|Vd"},
|
||||
{"inst": "stl1 Vs.D[#idx], [Xn|SP]" , "op": "0|idx:1|001101|000|00001|10000|1|Rn|Vs"},
|
||||
{"inst": "stlur Bs, [Xn|SP, #soff]" , "op": "00011101|000|soff:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Hs, [Xn|SP, #soff]" , "op": "01011101|000|soff:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Ss, [Xn|SP, #soff]" , "op": "10011101|000|soff:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Ds, [Xn|SP, #soff]" , "op": "11011101|000|soff:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Qs, [Xn|SP, #soff]" , "op": "00011101|100|soff:9|10|Rn|Vs"}
|
||||
{"inst": "stlur Bs, [Xn|SP, #offS]" , "op": "00011101|000|offS:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Hs, [Xn|SP, #offS]" , "op": "01011101|000|offS:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Ss, [Xn|SP, #offS]" , "op": "10011101|000|offS:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Ds, [Xn|SP, #offS]" , "op": "11011101|000|offS:9|10|Rn|Vs"},
|
||||
{"inst": "stlur Qs, [Xn|SP, #offS]" , "op": "00011101|100|offS:9|10|Rn|Vs"}
|
||||
]},
|
||||
|
||||
{"category": "ASIMD", "ext": "RDM", "data": [
|
||||
|
||||
@@ -2626,7 +2626,7 @@
|
||||
{"category": "AVX SIMD", "ext": "AVX SM3", "data": [
|
||||
{"inst": "vsm3msg1 X:xmm, xmm, xmm/m128" , "op": "RVM: VEX.128.NP.0F38.W0 DA /r"},
|
||||
{"inst": "vsm3msg2 X:xmm, xmm, xmm/m128" , "op": "RVM: VEX.128.66.0F38.W0 DA /r"},
|
||||
{"inst": "vsm3rnds2 X:xmm, xmm, xmm/m128, ib/ub" , "op": "RVM: VEX.128.66.0F3A.W0 DE /r /ib"}
|
||||
{"inst": "vsm3rnds2 X:xmm, xmm, xmm/m128, ib/ub" , "op": "RVM: VEX.128.66.0F3A.W0 DE /r ib"}
|
||||
]},
|
||||
|
||||
{"category": "AVX SIMD", "ext": "AVX SM4", "data": [
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
//!
|
||||
//! ### Register Operands
|
||||
//!
|
||||
//! - \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::Reg - Base class of all AArch32/AArch64 registers.
|
||||
//! - \ref a64::Gp - General purpose register (AArch64):
|
||||
//! - \ref a64::GpW - 32-bit general purpose register (AArch64).
|
||||
//! - \ref a64::GpX - 64-bit general purpose register (AArch64).
|
||||
//! - \ref arm::Vec - Vector (SIMD) register:
|
||||
//! - \ref arm::VecB - 8-bit SIMD register.
|
||||
//! - \ref arm::VecH - 16-bit SIMD register.
|
||||
|
||||
@@ -18,14 +18,16 @@
|
||||
//!
|
||||
//! ### Emitters
|
||||
//!
|
||||
//! - AArch64
|
||||
//! - AArch32
|
||||
//! - \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).
|
||||
//!
|
||||
//! - AArch64
|
||||
//! - \ref a64::Assembler - AArch64 assembler (must read, provides examples).
|
||||
//! - \ref a64::Builder - AArch64 builder.
|
||||
//! - \ref a64::Compiler - AArch64 compiler.
|
||||
//! - \ref a64::Emitter - AArch64 emitter (abstract).
|
||||
//!
|
||||
//! ### Supported Instructions
|
||||
@@ -46,10 +48,11 @@
|
||||
//!
|
||||
//! ### Register Operands
|
||||
//!
|
||||
//! - \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 (AArch64 only).
|
||||
//! - \ref arm::Reg - Base class of all AArch32/AArch64 registers.
|
||||
//! - \ref a32::Gp - 32-bit general purpose register used by AArch32:
|
||||
//! - \ref a64::Gp - 32-bit or 64-bit general purpose register used by AArch64:
|
||||
//! - \ref a64::GpW - 32-bit register (AArch64).
|
||||
//! - \ref a64::GpX - 64-bit register (AArch64).
|
||||
//! - \ref arm::Vec - Vector (SIMD) register:
|
||||
//! - \ref arm::VecB - 8-bit SIMD register (AArch64 only).
|
||||
//! - \ref arm::VecH - 16-bit SIMD register (AArch64 only).
|
||||
|
||||
@@ -716,8 +716,6 @@ static inline bool checkValidRegs(const Operand_& o0, const Operand_& o1, const
|
||||
|
||||
Assembler::Assembler(CodeHolder* code) noexcept : BaseAssembler() {
|
||||
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -803,7 +801,7 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
|
||||
Operand_ opArray[Globals::kMaxOpCount];
|
||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||
|
||||
err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
|
||||
err = _funcs.validate(BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
|
||||
if (ASMJIT_UNLIKELY(err))
|
||||
goto Failed;
|
||||
}
|
||||
@@ -2266,7 +2264,7 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
|
||||
if (m.hasBaseReg()) {
|
||||
// [Base {Offset | Index}]
|
||||
if (m.hasIndex()) {
|
||||
uint32_t opt = armShiftOpToLdStOptMap[m.predicate()];
|
||||
uint32_t opt = armShiftOpToLdStOptMap[size_t(m.shiftOp())];
|
||||
if (opt == 0xFF)
|
||||
goto InvalidAddress;
|
||||
|
||||
@@ -2352,7 +2350,7 @@ Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, co
|
||||
if (m.hasBaseReg()) {
|
||||
// [Base {Offset | Index}]
|
||||
if (m.hasIndex()) {
|
||||
uint32_t opt = armShiftOpToLdStOptMap[m.predicate()];
|
||||
uint32_t opt = armShiftOpToLdStOptMap[size_t(m.shiftOp())];
|
||||
if (opt == 0xFF)
|
||||
goto InvalidAddress;
|
||||
|
||||
@@ -4513,7 +4511,7 @@ Case_BaseLdurStur:
|
||||
if (m.hasBaseReg()) {
|
||||
// [Base {Offset | Index}]
|
||||
if (m.hasIndex()) {
|
||||
uint32_t opt = armShiftOpToLdStOptMap[m.predicate()];
|
||||
uint32_t opt = armShiftOpToLdStOptMap[size_t(m.shiftOp())];
|
||||
if (opt == 0xFFu)
|
||||
goto InvalidAddress;
|
||||
|
||||
@@ -5169,6 +5167,10 @@ Error Assembler::align(AlignMode alignMode, uint32_t alignment) {
|
||||
|
||||
Error Assembler::onAttach(CodeHolder* code) noexcept {
|
||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||
|
||||
_instructionAlignment = uint8_t(4);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class ASMJIT_VIRTAPI Assembler
|
||||
public:
|
||||
typedef BaseAssembler Base;
|
||||
|
||||
//! \name Construction / Destruction
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
|
||||
ASMJIT_API Assembler(CodeHolder* code = nullptr) noexcept;
|
||||
@@ -37,9 +37,6 @@ public:
|
||||
//! Gets whether the current ARM mode is THUMB (alternative to 32-bit ARM encoding).
|
||||
ASMJIT_INLINE_NODEBUG bool isInThumbMode() const noexcept { return _environment.isArchThumb(); }
|
||||
|
||||
//! Gets the current code alignment of the current mode (ARM vs THUMB).
|
||||
ASMJIT_INLINE_NODEBUG uint32_t codeAlignment() const noexcept { return isInThumbMode() ? 2 : 4; }
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Emit
|
||||
|
||||
@@ -17,8 +17,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
|
||||
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
|
||||
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -28,13 +26,19 @@ Builder::~Builder() noexcept {}
|
||||
// =====================
|
||||
|
||||
Error Builder::onAttach(CodeHolder* code) noexcept {
|
||||
return Base::onAttach(code);
|
||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||
|
||||
_instructionAlignment = uint8_t(4);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Builder::onDetach(CodeHolder* code) noexcept {
|
||||
return Base::onDetach(code);
|
||||
}
|
||||
|
||||
|
||||
// a64::Builder - Finalize
|
||||
// =======================
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
|
||||
Compiler::Compiler(CodeHolder* code) noexcept : BaseCompiler() {
|
||||
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -37,6 +35,9 @@ Error Compiler::onAttach(CodeHolder* code) noexcept {
|
||||
return err;
|
||||
}
|
||||
|
||||
_instructionAlignment = uint8_t(4);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
|
||||
else
|
||||
ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
|
||||
|
||||
mem.resetToFixedOffset();
|
||||
mem.resetOffsetMode();
|
||||
|
||||
if (i == 0 && frame.hasPreservedFP()) {
|
||||
ASMJIT_PROPAGATE(emitter->mov(x29, sp));
|
||||
@@ -427,7 +427,7 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
|
||||
else
|
||||
ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
|
||||
|
||||
mem.resetToFixedOffset();
|
||||
mem.resetOffsetMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
//! ARM emitter.
|
||||
//!
|
||||
//! NOTE: This class cannot be instantiated, you can only cast to it and use it as emitter that emits to either
|
||||
//! \ref Assembler, \ref Builder, or \ref Compiler (use withcaution with \ref Compiler as it expects virtual
|
||||
//! \ref Assembler, \ref Builder, or \ref Compiler (use with caution with \ref Compiler as it expects virtual
|
||||
//! registers to be used).
|
||||
template<typename This>
|
||||
struct EmitterExplicitT {
|
||||
@@ -79,8 +79,8 @@ struct EmitterExplicitT {
|
||||
|
||||
// These two are unfortunately reported by the sanitizer. We know what we do, however, the sanitizer doesn't.
|
||||
// I have tried to use reinterpret_cast instead, but that would generate bad code when compiled by MSC.
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF inline This* _emitter() noexcept { return static_cast<This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF inline const This* _emitter() const noexcept { return static_cast<const This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF ASMJIT_INLINE_NODEBUG This* _emitter() noexcept { return static_cast<This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF ASMJIT_INLINE_NODEBUG const This* _emitter() const noexcept { return static_cast<const This*>(this); }
|
||||
|
||||
//! \endcond
|
||||
|
||||
|
||||
@@ -29,12 +29,10 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
|
||||
Arch arch,
|
||||
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
|
||||
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
// Format instruction options and instruction mnemonic.
|
||||
InstId instId = inst.realId();
|
||||
if (instId < Inst::_kIdCount)
|
||||
ASMJIT_PROPAGATE(InstInternal::instIdToString(arch, instId, sb));
|
||||
ASMJIT_PROPAGATE(InstInternal::instIdToString(instId, sb));
|
||||
else
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
|
||||
// a64 uses everything from arm namespace and adds into it.
|
||||
using namespace arm;
|
||||
|
||||
//! \addtogroup asmjit_a64
|
||||
//! \{
|
||||
|
||||
|
||||
@@ -15,65 +15,22 @@
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
|
||||
namespace InstInternal {
|
||||
|
||||
// a64::InstInternal - Text
|
||||
// ========================
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noexcept {
|
||||
Error instIdToString(InstId instId, String& output) noexcept {
|
||||
uint32_t realId = instId & uint32_t(InstIdParts::kRealId);
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId)))
|
||||
return DebugUtils::errored(kErrorInvalidInstruction);
|
||||
|
||||
|
||||
char nameData[32];
|
||||
size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[realId], InstDB::_instNameStringTable);
|
||||
|
||||
return output.append(nameData, nameSize);
|
||||
return InstNameUtils::decode(output, InstDB::_instNameIndexTable[realId], InstDB::_instNameStringTable);
|
||||
}
|
||||
|
||||
InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!s))
|
||||
return Inst::kIdNone;
|
||||
|
||||
if (len == SIZE_MAX)
|
||||
len = strlen(s);
|
||||
|
||||
if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize))
|
||||
return Inst::kIdNone;
|
||||
|
||||
uint32_t prefix = uint32_t(s[0]) - 'a';
|
||||
if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
|
||||
return Inst::kIdNone;
|
||||
|
||||
size_t base = InstDB::instNameIndex[prefix].start;
|
||||
size_t end = InstDB::instNameIndex[prefix].end;
|
||||
|
||||
if (ASMJIT_UNLIKELY(!base))
|
||||
return Inst::kIdNone;
|
||||
|
||||
char nameData[32];
|
||||
for (size_t lim = end - base; lim != 0; lim >>= 1) {
|
||||
size_t instId = base + (lim >> 1);
|
||||
size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable);
|
||||
|
||||
int result = Support::compareStringViews(s, len, nameData, nameSize);
|
||||
if (result < 0)
|
||||
continue;
|
||||
|
||||
if (result > 0) {
|
||||
base = instId + 1;
|
||||
lim--;
|
||||
continue;
|
||||
}
|
||||
|
||||
return InstId(instId);
|
||||
}
|
||||
|
||||
return Inst::kIdNone;
|
||||
InstId stringToInstId(const char* s, size_t len) noexcept {
|
||||
return InstNameUtils::find(s, len, InstDB::instNameIndex, InstDB::_instNameIndexTable, InstDB::_instNameStringTable);
|
||||
}
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
@@ -81,9 +38,9 @@ InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexce
|
||||
// ============================
|
||||
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
ASMJIT_FAVOR_SIZE Error InstInternal::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
ASMJIT_FAVOR_SIZE Error validate(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
// TODO:
|
||||
DebugUtils::unused(arch, inst, operands, opCount, validationFlags);
|
||||
DebugUtils::unused(inst, operands, opCount, validationFlags);
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_NO_VALIDATION
|
||||
@@ -127,13 +84,7 @@ static const InstRWInfoData instRWInfoData[] = {
|
||||
|
||||
static const uint8_t elementTypeSize[8] = { 0, 1, 2, 4, 8, 4, 4, 0 };
|
||||
|
||||
Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||
// Unused in Release configuration as the assert is not compiled in.
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
// Only called when `arch` matches X86 family.
|
||||
ASMJIT_ASSERT(Environment::isFamilyARM(arch));
|
||||
|
||||
Error queryRWInfo(const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||
// Get the instruction data.
|
||||
uint32_t realId = inst.id() & uint32_t(InstIdParts::kRealId);
|
||||
|
||||
@@ -243,8 +194,7 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_*
|
||||
}
|
||||
|
||||
if (memOp.hasIndex()) {
|
||||
op.addOpFlags(OpRWFlags::kMemIndexRead);
|
||||
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexWrite : OpRWFlags::kNone);
|
||||
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexRW : OpRWFlags::kMemIndexRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,13 +208,15 @@ Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_*
|
||||
// =================================
|
||||
|
||||
#ifndef ASMJIT_NO_INTROSPECTION
|
||||
Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
|
||||
Error queryFeatures(const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
|
||||
// TODO: [ARM] QueryFeatures not implemented yet.
|
||||
DebugUtils::unused(arch, inst, operands, opCount, out);
|
||||
DebugUtils::unused(inst, operands, opCount, out);
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_NO_INTROSPECTION
|
||||
|
||||
} // {InstInternal}
|
||||
|
||||
// a64::InstInternal - Unit
|
||||
// ========================
|
||||
|
||||
|
||||
@@ -18,17 +18,17 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
namespace InstInternal {
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
Error ASMJIT_CDECL instIdToString(Arch arch, InstId instId, String& output) noexcept;
|
||||
InstId ASMJIT_CDECL stringToInstId(Arch arch, const char* s, size_t len) noexcept;
|
||||
Error ASMJIT_CDECL instIdToString(InstId instId, String& output) noexcept;
|
||||
InstId ASMJIT_CDECL stringToInstId(const char* s, size_t len) noexcept;
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
Error ASMJIT_CDECL validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
|
||||
Error ASMJIT_CDECL validate(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
|
||||
#endif // !ASMJIT_NO_VALIDATION
|
||||
|
||||
#ifndef ASMJIT_NO_INTROSPECTION
|
||||
Error ASMJIT_CDECL queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
|
||||
Error ASMJIT_CDECL queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept;
|
||||
Error ASMJIT_CDECL queryRWInfo(const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
|
||||
Error ASMJIT_CDECL queryFeatures(const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept;
|
||||
#endif // !ASMJIT_NO_INTROSPECTION
|
||||
|
||||
} // {InstInternal}
|
||||
|
||||
@@ -1851,6 +1851,42 @@ const InstDB::CommonInfo InstDB::commonData[] = {
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
// ${NameData:Begin}
|
||||
// ------------------- Automatically generated, do not edit -------------------
|
||||
const InstNameIndex InstDB::instNameIndex = {{
|
||||
{ Inst::kIdAdc , Inst::kIdAnd_v + 1 },
|
||||
{ Inst::kIdB , Inst::kIdBsl_v + 1 },
|
||||
{ Inst::kIdCas , Inst::kIdCnt_v + 1 },
|
||||
{ Inst::kIdDc , Inst::kIdDup_v + 1 },
|
||||
{ Inst::kIdEon , Inst::kIdExt_v + 1 },
|
||||
{ Inst::kIdFabd_v , Inst::kIdFsub_v + 1 },
|
||||
{ Inst::kIdGmi , Inst::kIdGmi + 1 },
|
||||
{ Inst::kIdHint , Inst::kIdHvc + 1 },
|
||||
{ Inst::kIdIc , Inst::kIdIns_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdLdadd , Inst::kIdLdur_v + 1 },
|
||||
{ Inst::kIdMadd , Inst::kIdMvni_v + 1 },
|
||||
{ Inst::kIdNeg , Inst::kIdNot_v + 1 },
|
||||
{ Inst::kIdOrn , Inst::kIdOrr_v + 1 },
|
||||
{ Inst::kIdPacda , Inst::kIdPmull2_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdRbit , Inst::kIdRsubhn2_v + 1 },
|
||||
{ Inst::kIdSbc , Inst::kIdSxtl2_v + 1 },
|
||||
{ Inst::kIdTlbi , Inst::kIdTrn2_v + 1 },
|
||||
{ Inst::kIdUbfiz , Inst::kIdUzp2_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdWfe , Inst::kIdWfi + 1 },
|
||||
{ Inst::kIdXaflag , Inst::kIdXtn2_v + 1 },
|
||||
{ Inst::kIdYield , Inst::kIdYield + 1 },
|
||||
{ Inst::kIdZip1_v , Inst::kIdZip2_v + 1 }
|
||||
}, uint16_t(9)};
|
||||
|
||||
const char InstDB::_instNameStringTable[] =
|
||||
"autia1716autibldsmaxalhldsminalldumaxallduminalsha256su0sha512su1sm3partwsqrshru"
|
||||
"nldaddalldclralldeoralldsetallbstsmaxstsminstumaxstuminfrint32z64x64zh2sqdmlalsl"
|
||||
"2sqdmulsqrdmlaulhn2sqshruuqrshrspcrc32cstaddstclrsteorstsetxpaclbfcvtbfmlaltfcvt"
|
||||
"xfjcvtzfmaxnmfminnmfrsqrraddrsubsha1sm3tt12a2bsm4ekeysqxtuuqshrursqrsetfrev8";
|
||||
|
||||
|
||||
const uint32_t InstDB::_instNameIndexTable[] = {
|
||||
0x80000000, // Small ''.
|
||||
0x80000C81, // Small 'adc'.
|
||||
@@ -2618,42 +2654,6 @@ const uint32_t InstDB::_instNameIndexTable[] = {
|
||||
0x800E413A, // Small 'zip1'.
|
||||
0x800EC13A // Small 'zip2'.
|
||||
};
|
||||
|
||||
const char InstDB::_instNameStringTable[] =
|
||||
"autia1716autibldsmaxalhldsminalldumaxallduminalsha256su0sha512su1sm3partwsqrshru"
|
||||
"nldaddalldclralldeoralldsetallbstsmaxstsminstumaxstuminfrint32z64x64zh2sqdmlalsl"
|
||||
"2sqdmulsqrdmlaulhn2sqshruuqrshrspcrc32cstaddstclrsteorstsetxpaclbfcvtbfmlaltfcvt"
|
||||
"xfjcvtzfmaxnmfminnmfrsqrraddrsubsha1sm3tt12a2bsm4ekeysqxtuuqshrursqrsetfrev8";
|
||||
|
||||
|
||||
const InstDB::InstNameIndex InstDB::instNameIndex[26] = {
|
||||
{ Inst::kIdAdc , Inst::kIdAnd_v + 1 },
|
||||
{ Inst::kIdB , Inst::kIdBsl_v + 1 },
|
||||
{ Inst::kIdCas , Inst::kIdCnt_v + 1 },
|
||||
{ Inst::kIdDc , Inst::kIdDup_v + 1 },
|
||||
{ Inst::kIdEon , Inst::kIdExt_v + 1 },
|
||||
{ Inst::kIdFabd_v , Inst::kIdFsub_v + 1 },
|
||||
{ Inst::kIdGmi , Inst::kIdGmi + 1 },
|
||||
{ Inst::kIdHint , Inst::kIdHvc + 1 },
|
||||
{ Inst::kIdIc , Inst::kIdIns_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdLdadd , Inst::kIdLdur_v + 1 },
|
||||
{ Inst::kIdMadd , Inst::kIdMvni_v + 1 },
|
||||
{ Inst::kIdNeg , Inst::kIdNot_v + 1 },
|
||||
{ Inst::kIdOrn , Inst::kIdOrr_v + 1 },
|
||||
{ Inst::kIdPacda , Inst::kIdPmull2_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdRbit , Inst::kIdRsubhn2_v + 1 },
|
||||
{ Inst::kIdSbc , Inst::kIdSxtl2_v + 1 },
|
||||
{ Inst::kIdTlbi , Inst::kIdTrn2_v + 1 },
|
||||
{ Inst::kIdUbfiz , Inst::kIdUzp2_v + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdWfe , Inst::kIdWfi + 1 },
|
||||
{ Inst::kIdXaflag , Inst::kIdXtn2_v + 1 },
|
||||
{ Inst::kIdYield , Inst::kIdYield + 1 },
|
||||
{ Inst::kIdZip1_v , Inst::kIdZip2_v + 1 }
|
||||
};
|
||||
// ----------------------------------------------------------------------------
|
||||
// ${NameData:End}
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
@@ -29,7 +29,7 @@ enum InstFlags : uint32_t {
|
||||
//! SIMD element access of half-words can only be used with v0..15.
|
||||
kInstFlagVH0_15 = 0x00000010u,
|
||||
|
||||
//! Instruction may consecutive registers if the number of operands is greater than 2.
|
||||
//! Instruction uses consecutive registers if the number of operands is greater than 2.
|
||||
kInstFlagConsecutive = 0x00000080u
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define ASMJIT_ARM_A64INSTDB_H_P_INCLUDED
|
||||
|
||||
#include "../core/codeholder.h"
|
||||
#include "../core/instdb_p.h"
|
||||
#include "../arm/a64instdb.h"
|
||||
#include "../arm/a64operand.h"
|
||||
|
||||
@@ -852,27 +853,13 @@ extern const SimdTblTbx simdTblTbx[2];
|
||||
|
||||
} // {EncodingData}
|
||||
|
||||
// a64::InstDB - InstNameIndex
|
||||
// ===========================
|
||||
|
||||
// ${NameLimits:Begin}
|
||||
// ------------------- Automatically generated, do not edit -------------------
|
||||
enum : uint32_t { kMaxNameSize = 9 };
|
||||
// ----------------------------------------------------------------------------
|
||||
// ${NameLimits:End}
|
||||
|
||||
struct InstNameIndex {
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
// a64::InstDB - Tables
|
||||
// ====================
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
extern const uint32_t _instNameIndexTable[];
|
||||
extern const InstNameIndex instNameIndex;
|
||||
extern const char _instNameStringTable[];
|
||||
extern const InstNameIndex instNameIndex[26];
|
||||
extern const uint32_t _instNameIndexTable[];
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
} // {InstDB}
|
||||
|
||||
@@ -13,24 +13,68 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
//! \addtogroup asmjit_a64
|
||||
//! \{
|
||||
|
||||
using arm::Reg;
|
||||
using arm::Mem;
|
||||
using arm::Gp;
|
||||
using arm::GpW;
|
||||
using arm::GpX;
|
||||
class GpW;
|
||||
class GpX;
|
||||
|
||||
using arm::Vec;
|
||||
using arm::VecB;
|
||||
using arm::VecH;
|
||||
using arm::VecS;
|
||||
using arm::VecD;
|
||||
using arm::VecV;
|
||||
//! General purpose register (AArch64).
|
||||
class Gp : public Reg {
|
||||
public:
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(Gp, Reg)
|
||||
|
||||
//! Special register id.
|
||||
enum Id : uint32_t {
|
||||
//! Register that depends on OS, could be used as TLS offset.
|
||||
kIdOs = 18,
|
||||
//! Frame pointer.
|
||||
kIdFp = 29,
|
||||
//! Link register.
|
||||
kIdLr = 30,
|
||||
//! Stack register id.
|
||||
kIdSp = 31,
|
||||
//! Zero register id.
|
||||
//!
|
||||
//! Although zero register has the same id as stack register it has a special treatment, because we need to be
|
||||
//! able to distinguish between these two at API level. Some instructions were designed to be used with SP and
|
||||
//! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing.
|
||||
//!
|
||||
//! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs,
|
||||
//! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction.
|
||||
kIdZr = 63
|
||||
};
|
||||
|
||||
//! Test whether this register is ZR register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isZR() const noexcept { return id() == kIdZr; }
|
||||
//! Test whether this register is SP register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isSP() const noexcept { return id() == kIdSp; }
|
||||
|
||||
//! Cast this register to a 32-bit W register (returns a new operand).
|
||||
ASMJIT_INLINE_NODEBUG GpW w() const noexcept;
|
||||
//! Cast this register to a 64-bit X register (returns a new operand).
|
||||
ASMJIT_INLINE_NODEBUG GpX x() const noexcept;
|
||||
};
|
||||
|
||||
//! 32-bit general purpose W register (AArch64).
|
||||
class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>); };
|
||||
//! 64-bit general purpose X register (AArch64).
|
||||
class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>); };
|
||||
|
||||
#ifndef _DOXYGEN
|
||||
ASMJIT_INLINE_NODEBUG GpW Gp::w() const noexcept { return GpW(id()); }
|
||||
ASMJIT_INLINE_NODEBUG GpX Gp::x() const noexcept { return GpX(id()); }
|
||||
#endif
|
||||
|
||||
#ifndef _DOXYGEN
|
||||
namespace regs {
|
||||
#endif
|
||||
|
||||
using namespace ::asmjit::arm::regs;
|
||||
//! Creates a 32-bit W register operand (ARM/AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr GpW w(uint32_t id) noexcept { return GpW(id); }
|
||||
//! Creates a 64-bit X register operand (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr GpX x(uint32_t id) noexcept { return GpX(id); }
|
||||
|
||||
using ::asmjit::arm::regs::s;
|
||||
using ::asmjit::arm::regs::d;
|
||||
using ::asmjit::arm::regs::v;
|
||||
|
||||
static constexpr GpW w0 = GpW(0);
|
||||
static constexpr GpW w1 = GpW(1);
|
||||
@@ -305,8 +349,91 @@ static constexpr VecV v31 = VecV(31);
|
||||
using namespace regs;
|
||||
#endif
|
||||
|
||||
//! \name Shift Operation Construction
|
||||
//! \{
|
||||
|
||||
//! Constructs a `UXTB #value` extend and shift (unsigned byte extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtb(uint32_t value) noexcept { return Shift(ShiftOp::kUXTB, value); }
|
||||
//! Constructs a `UXTH #value` extend and shift (unsigned hword extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxth(uint32_t value) noexcept { return Shift(ShiftOp::kUXTH, value); }
|
||||
//! Constructs a `UXTW #value` extend and shift (unsigned word extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtw(uint32_t value) noexcept { return Shift(ShiftOp::kUXTW, value); }
|
||||
//! Constructs a `UXTX #value` extend and shift (unsigned dword extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtx(uint32_t value) noexcept { return Shift(ShiftOp::kUXTX, value); }
|
||||
|
||||
//! Constructs a `SXTB #value` extend and shift (signed byte extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtb(uint32_t value) noexcept { return Shift(ShiftOp::kSXTB, value); }
|
||||
//! Constructs a `SXTH #value` extend and shift (signed hword extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxth(uint32_t value) noexcept { return Shift(ShiftOp::kSXTH, value); }
|
||||
//! Constructs a `SXTW #value` extend and shift (signed word extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtw(uint32_t value) noexcept { return Shift(ShiftOp::kSXTW, value); }
|
||||
//! Constructs a `SXTX #value` extend and shift (signed dword extend) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtx(uint32_t value) noexcept { return Shift(ShiftOp::kSXTX, value); }
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Memory Operand Construction
|
||||
//! \{
|
||||
|
||||
//! Creates `[base, offset]` memory operand (offset mode) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset);
|
||||
}
|
||||
|
||||
//! Creates `[base, offset]!` memory operand (pre-index mode) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPreIndex));
|
||||
}
|
||||
|
||||
//! Creates `[base], offset` memory operand (post-index mode) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPostIndex));
|
||||
}
|
||||
|
||||
//! Creates `[base, index]` memory operand (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
|
||||
return Mem(base, index);
|
||||
}
|
||||
|
||||
//! Creates `[base, index]!` memory operand (pre-index mode) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_pre(const Gp& base, const Gp& index) noexcept {
|
||||
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPreIndex));
|
||||
}
|
||||
|
||||
//! Creates `[base], index` memory operand (post-index mode) (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
|
||||
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPostIndex));
|
||||
}
|
||||
|
||||
//! Creates `[base, index, SHIFT_OP #shift]` memory operand (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
|
||||
return Mem(base, index, shift);
|
||||
}
|
||||
|
||||
//! Creates `[base, offset]` memory operand (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset);
|
||||
}
|
||||
|
||||
// TODO: [ARM] PC + offset address.
|
||||
#if 0
|
||||
//! Creates `[PC + offset]` (relative) memory operand.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
|
||||
return Mem(pc, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! \}
|
||||
|
||||
//! \}
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
//! \cond INTERNAL
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
ASMJIT_DEFINE_TYPE_ID(a64::GpW, TypeId::kInt32);
|
||||
ASMJIT_DEFINE_TYPE_ID(a64::GpX, TypeId::kInt64);
|
||||
ASMJIT_END_NAMESPACE
|
||||
//! \endcond
|
||||
|
||||
#endif // ASMJIT_ARM_A64OPERAND_H_INCLUDED
|
||||
|
||||
@@ -131,7 +131,7 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
||||
InstId instId = inst->id();
|
||||
uint32_t opCount = inst->opCount();
|
||||
const Operand* opArray = inst->operands();
|
||||
ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo));
|
||||
ASMJIT_PROPAGATE(InstInternal::queryRWInfo(inst->baseInst(), opArray, opCount, &rwInfo));
|
||||
|
||||
const InstDB::InstInfo& instInfo = InstDB::infoById(instId);
|
||||
uint32_t singleRegOps = 0;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "../core/misc_p.h"
|
||||
#include "../core/support.h"
|
||||
#include "../arm/armformatter_p.h"
|
||||
#include "../arm/armoperand.h"
|
||||
#include "../arm/a64operand.h"
|
||||
#include "../arm/a64instapi_p.h"
|
||||
#include "../arm/a64instdb_p.h"
|
||||
|
||||
@@ -178,7 +178,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatCondCode(String& sb, CondCode c
|
||||
static const char condCodeData[] =
|
||||
"al\0" "na\0"
|
||||
"eq\0" "ne\0"
|
||||
"cs\0" "cc\0" "mi\0" "pl\0" "vs\0" "vc\0"
|
||||
"hs\0" "lo\0" "mi\0" "pl\0" "vs\0" "vc\0"
|
||||
"hi\0" "ls\0" "ge\0" "lt\0" "gt\0" "le\0"
|
||||
"<Unknown>";
|
||||
return sb.append(condCodeData + Support::min<uint32_t>(uint32_t(cc), 16u) * 3);
|
||||
@@ -209,6 +209,25 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatShiftOp(String& sb, ShiftOp shi
|
||||
// arm::FormatterInternal - Format Register
|
||||
// ========================================
|
||||
|
||||
struct FormatElementData {
|
||||
char letter;
|
||||
uint8_t elementCount;
|
||||
uint8_t onlyIndex;
|
||||
uint8_t reserved;
|
||||
};
|
||||
|
||||
static constexpr FormatElementData formatElementDataTable[9] = {
|
||||
{ '?' , 0 , 0, 0 }, // None
|
||||
{ 'b' , 16, 0, 0 }, // bX or b[index]
|
||||
{ 'h' , 8 , 0, 0 }, // hX or h[index]
|
||||
{ 's' , 4 , 0, 0 }, // sX or s[index]
|
||||
{ 'd' , 2 , 0, 0 }, // dX or d[index]
|
||||
{ 'b' , 4 , 1, 0 }, // ?? or b4[index]
|
||||
{ 'h' , 2 , 1, 0 }, // ?? or h2[index]
|
||||
{ '?' , 0 , 0, 0 }, // invalid (possibly stored in Operand)
|
||||
{ '?' , 0 , 0, 0 } // invalid (never stored in Operand, bug...)
|
||||
};
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
||||
String& sb,
|
||||
FormatFlags flags,
|
||||
@@ -265,31 +284,22 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
||||
if (Environment::is64Bit(arch)) {
|
||||
letter = 'w';
|
||||
|
||||
if (rId == Gp::kIdZr)
|
||||
if (rId == a64::Gp::kIdZr)
|
||||
return sb.append("wzr", 3);
|
||||
|
||||
if (rId == Gp::kIdSp)
|
||||
if (rId == a64::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)
|
||||
if (rId == a64::Gp::kIdZr)
|
||||
return sb.append("xzr", 3);
|
||||
if (rId == Gp::kIdSp)
|
||||
if (rId == a64::Gp::kIdSp)
|
||||
return sb.append("sp", 2);
|
||||
|
||||
letter = 'x';
|
||||
@@ -300,7 +310,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
||||
ASMJIT_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("<Reg-%u>?$u", uint32_t(regType), rId));
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("<Reg-%u>?%u", uint32_t(regType), rId));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -309,53 +319,68 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
||||
}
|
||||
|
||||
if (elementType) {
|
||||
char elementLetter = '\0';
|
||||
uint32_t elementCount = 0;
|
||||
if (elementType > a64::Vec::kElementTypeCount)
|
||||
elementType = a64::Vec::kElementTypeCount;
|
||||
|
||||
switch (elementType) {
|
||||
case Vec::kElementTypeB:
|
||||
elementLetter = 'b';
|
||||
elementCount = 16;
|
||||
break;
|
||||
FormatElementData elementData = formatElementDataTable[elementType];
|
||||
uint32_t elementCount = elementData.elementCount;
|
||||
|
||||
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 (regType == RegType::kARM_VecD) {
|
||||
elementCount /= 2u;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
ASMJIT_PROPAGATE(sb.append('.'));
|
||||
if (elementCount) {
|
||||
ASMJIT_PROPAGATE(sb.appendUInt(elementCount));
|
||||
}
|
||||
ASMJIT_PROPAGATE(sb.append(elementData.letter));
|
||||
}
|
||||
else if (elementIndex != 0xFFFFFFFFu) {
|
||||
// This should only be used by AArch32 - AArch64 requires an additional elementType in index[].
|
||||
|
||||
if (elementIndex != 0xFFFFFFFFu) {
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("[%u]", elementIndex));
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegisterList(
|
||||
String& sb,
|
||||
FormatFlags flags,
|
||||
const BaseEmitter* emitter,
|
||||
Arch arch,
|
||||
RegType regType,
|
||||
uint32_t rMask) noexcept {
|
||||
|
||||
bool first = true;
|
||||
|
||||
ASMJIT_PROPAGATE(sb.append('{'));
|
||||
while (rMask != 0u) {
|
||||
uint32_t start = Support::ctz(rMask);
|
||||
uint32_t count = 0u;
|
||||
|
||||
uint32_t mask = 1u << start;
|
||||
do {
|
||||
rMask &= ~mask;
|
||||
mask <<= 1u;
|
||||
count++;
|
||||
} while (rMask & mask);
|
||||
|
||||
if (!first)
|
||||
ASMJIT_PROPAGATE(sb.append(", "));
|
||||
|
||||
ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, regType, start, 0, 0xFFFFFFFFu));
|
||||
if (count >= 2u) {
|
||||
ASMJIT_PROPAGATE(sb.append('-'));
|
||||
ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, regType, start + count - 1, 0, 0xFFFFFFFFu));
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
ASMJIT_PROPAGATE(sb.append('}'));
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
// a64::FormatterInternal - Format Operand
|
||||
// =======================================
|
||||
|
||||
@@ -434,7 +459,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
||||
if (m.hasShift()) {
|
||||
ASMJIT_PROPAGATE(sb.append(' '));
|
||||
if (!m.isPreOrPost())
|
||||
ASMJIT_PROPAGATE(formatShiftOp(sb, (ShiftOp)m.predicate()));
|
||||
ASMJIT_PROPAGATE(formatShiftOp(sb, m.shiftOp()));
|
||||
ASMJIT_PROPAGATE(sb.appendFormat(" %u", m.shift()));
|
||||
}
|
||||
|
||||
@@ -464,6 +489,11 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
||||
return Formatter::formatLabel(sb, flags, emitter, op.id());
|
||||
}
|
||||
|
||||
if (op.isRegList()) {
|
||||
const BaseRegList& regList = op.as<BaseRegList>();
|
||||
return formatRegisterList(sb, flags, emitter, arch, regList.type(), regList.list());
|
||||
}
|
||||
|
||||
return sb.append("<None>");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ Error ASMJIT_CDECL formatRegister(
|
||||
uint32_t elementType = 0,
|
||||
uint32_t elementIndex = 0xFFFFFFFF) noexcept;
|
||||
|
||||
Error ASMJIT_CDECL formatRegisterList(
|
||||
String& sb,
|
||||
FormatFlags flags,
|
||||
const BaseEmitter* emitter,
|
||||
Arch arch,
|
||||
RegType regType,
|
||||
uint32_t rMask) noexcept;
|
||||
|
||||
Error ASMJIT_CDECL formatOperand(
|
||||
String& sb,
|
||||
FormatFlags flags,
|
||||
|
||||
@@ -14,8 +14,4 @@
|
||||
//!
|
||||
//! API shared between AArch32 & AArch64 backends.
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
#endif // ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
|
||||
|
||||
@@ -19,10 +19,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
||||
class Reg;
|
||||
class Mem;
|
||||
|
||||
class Gp;
|
||||
class GpW;
|
||||
class GpX;
|
||||
|
||||
class Vec;
|
||||
class VecB;
|
||||
class VecH;
|
||||
@@ -30,7 +26,7 @@ class VecS;
|
||||
class VecD;
|
||||
class VecV;
|
||||
|
||||
//! Register traits (ARM/AArch64).
|
||||
//! Register traits (AArch32/AArch64).
|
||||
//!
|
||||
//! Register traits contains information about a particular register type. It's used by asmjit to setup register
|
||||
//! information on-the-fly and to populate tables that contain register information (this way it's possible to
|
||||
@@ -39,27 +35,31 @@ template<RegType kRegType>
|
||||
struct RegTraits : public BaseRegTraits {};
|
||||
|
||||
//! \cond
|
||||
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
|
||||
// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId |
|
||||
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
|
||||
ASMJIT_DEFINE_REG_TRAITS(GpW , RegType::kARM_GpW , RegGroup::kGp , 4 , 32, TypeId::kInt32 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(GpX , RegType::kARM_GpX , RegGroup::kGp , 8 , 32, TypeId::kInt64 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(VecB , RegType::kARM_VecB , RegGroup::kVec , 1 , 32, TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(VecH , RegType::kARM_VecH , RegGroup::kVec , 2 , 32, TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(VecS , RegType::kARM_VecS , RegGroup::kVec , 4 , 32, TypeId::kInt32x1 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(VecD , RegType::kARM_VecD , RegGroup::kVec , 8 , 32, TypeId::kInt32x2 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(VecV , RegType::kARM_VecV , RegGroup::kVec , 16, 32, TypeId::kInt32x4 );
|
||||
// <--------------------+------------------------+------------------------+---+------------------+
|
||||
// | Reg-Type | Reg-Group |Sz | TypeId |
|
||||
// <--------------------+------------------------+------------------------+---+------------------+
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpW , RegGroup::kGp , 4 , TypeId::kInt32 ); // AArch32 & AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpX , RegGroup::kGp , 8 , TypeId::kInt64 ); // AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecB , RegGroup::kVec , 1 , TypeId::kVoid ); // AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecH , RegGroup::kVec , 2 , TypeId::kVoid ); // AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecS , RegGroup::kVec , 4 , TypeId::kInt32x1 ); // AArch32 & AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecD , RegGroup::kVec , 8 , TypeId::kInt32x2 ); // AArch32 & AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecV , RegGroup::kVec , 16, TypeId::kInt32x4 ); // AArch32 & AArch64
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_PC , RegGroup::kPC , 8 , TypeId::kInt64 ); // AArch64
|
||||
//! \endcond
|
||||
|
||||
//! Register (ARM).
|
||||
//! Register operand that can represent AArch32 and AArch64 registers.
|
||||
class Reg : public BaseReg {
|
||||
public:
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
|
||||
|
||||
//! Gets whether the register is a `R|W` register (32-bit).
|
||||
//! Gets whether the register is either `R` or `W` register (32-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGpR() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
||||
//! Gets whether the register is either `R` or `W` register (32-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
||||
//! Gets whether the register is an `X` register (64-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
|
||||
|
||||
//! Gets whether the register is a VEC-B register (8-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
||||
//! Gets whether the register is a VEC-H register (16-bit).
|
||||
@@ -70,10 +70,8 @@ public:
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
||||
//! Gets whether the register is a VEC-Q register (128-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
||||
|
||||
//! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
|
||||
|
||||
//! Gets whether the register is a VEC-V register (128-bit).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
||||
|
||||
@@ -99,7 +97,7 @@ public:
|
||||
static ASMJIT_INLINE_NODEBUG TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
|
||||
|
||||
template<RegType kRegType>
|
||||
static ASMJIT_INLINE_NODEBUG OperandSignature signatureOfT() noexcept { return RegTraits<kRegType>::kSignature; }
|
||||
static ASMJIT_INLINE_NODEBUG OperandSignature signatureOfT() noexcept { return OperandSignature{RegTraits<kRegType>::kSignature}; }
|
||||
|
||||
static ASMJIT_INLINE_NODEBUG bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
|
||||
static ASMJIT_INLINE_NODEBUG bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
|
||||
@@ -120,45 +118,16 @@ public:
|
||||
static ASMJIT_INLINE_NODEBUG bool isVecV(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecV(op)) & unsigned(op.id() == id)); }
|
||||
};
|
||||
|
||||
//! General purpose register (ARM).
|
||||
class Gp : public Reg {
|
||||
//! Vector register base - a common base for both AArch32 & AArch64 vector register.
|
||||
class BaseVec : public Reg {
|
||||
public:
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(Gp, Reg)
|
||||
|
||||
//! Special register id.
|
||||
enum Id : uint32_t {
|
||||
//! Register that depends on OS, could be used as TLS offset.
|
||||
kIdOs = 18,
|
||||
//! Frame pointer.
|
||||
kIdFp = 29,
|
||||
//! Link register.
|
||||
kIdLr = 30,
|
||||
//! Stack register id.
|
||||
kIdSp = 31,
|
||||
//! Zero register id.
|
||||
//!
|
||||
//! Although zero register has the same id as stack register it has a special treatment, because we need to be
|
||||
//! able to distinguish between these two at API level. Some intructions were designed to be used with SP and
|
||||
//! some other with ZR - so we need a way to distinguish these two to make sure we emit the right thing.
|
||||
//!
|
||||
//! The number 63 is not random, when you perform `id & 31` you would always get 31 for both SP and ZR inputs,
|
||||
//! which is the identifier used by AArch64 ISA to encode either SP or ZR depending on the instruction.
|
||||
kIdZr = 63
|
||||
};
|
||||
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isZR() const noexcept { return id() == kIdZr; }
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isSP() const noexcept { return id() == kIdSp; }
|
||||
|
||||
//! Cast this register to a 32-bit R|W.
|
||||
ASMJIT_INLINE_NODEBUG GpW w() const noexcept;
|
||||
//! Cast this register to a 64-bit X.
|
||||
ASMJIT_INLINE_NODEBUG GpX x() const noexcept;
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(BaseVec, Reg)
|
||||
};
|
||||
|
||||
//! Vector register (ARM).
|
||||
class Vec : public Reg {
|
||||
class Vec : public BaseVec {
|
||||
public:
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(Vec, Reg)
|
||||
ASMJIT_DEFINE_ABSTRACT_REG(Vec, BaseVec)
|
||||
|
||||
//! Additional signature bits used by arm::Vec.
|
||||
enum AdditionalBits : uint32_t {
|
||||
@@ -219,7 +188,7 @@ public:
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool hasElementType() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask>(); }
|
||||
//! Returns whether the register has element index (it's an element index access).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
|
||||
//! Returns whether the reggister has element type or element index (or both).
|
||||
//! Returns whether the register has element type or element index (or both).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool hasElementTypeOrIndex() const noexcept { return _signature.hasField<kSignatureRegElementTypeMask | kSignatureRegElementFlagMask>(); }
|
||||
|
||||
//! Returns element type of the register.
|
||||
@@ -310,11 +279,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//! 32-bit GPW (AArch64) and/or GPR (ARM/AArch32) register.
|
||||
class GpW : public Gp { ASMJIT_DEFINE_FINAL_REG(GpW, Gp, RegTraits<RegType::kARM_GpW>) };
|
||||
//! 64-bit GPX (AArch64) register.
|
||||
class GpX : public Gp { ASMJIT_DEFINE_FINAL_REG(GpX, Gp, RegTraits<RegType::kARM_GpX>) };
|
||||
|
||||
//! 8-bit view (S) of VFP/SIMD register.
|
||||
class VecB : public Vec { ASMJIT_DEFINE_FINAL_REG(VecB, Vec, RegTraits<RegType::kARM_VecB>) };
|
||||
//! 16-bit view (S) of VFP/SIMD register.
|
||||
@@ -326,9 +290,6 @@ class VecD : public Vec { ASMJIT_DEFINE_FINAL_REG(VecD, Vec, RegTraits<RegType::
|
||||
//! 128-bit vector register (Q or V).
|
||||
class VecV : public Vec { ASMJIT_DEFINE_FINAL_REG(VecV, Vec, RegTraits<RegType::kARM_VecV>) };
|
||||
|
||||
ASMJIT_INLINE_NODEBUG GpW Gp::w() const noexcept { return GpW(id()); }
|
||||
ASMJIT_INLINE_NODEBUG GpX Gp::x() const noexcept { return GpX(id()); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG VecB Vec::b() const noexcept { return VecB(id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecH Vec::h() const noexcept { return VecH(id()); }
|
||||
ASMJIT_INLINE_NODEBUG VecS Vec::s() const noexcept { return VecS(id()); }
|
||||
@@ -356,10 +317,6 @@ ASMJIT_INLINE_NODEBUG VecV Vec::d2() const noexcept { return VecV(OperandSignatu
|
||||
namespace regs {
|
||||
#endif
|
||||
|
||||
//! Creates a 32-bit W register operand (ARM/AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr GpW w(uint32_t id) noexcept { return GpW(id); }
|
||||
//! Creates a 64-bit X register operand (AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr GpX x(uint32_t id) noexcept { return GpX(id); }
|
||||
//! Creates a 32-bit S register operand (ARM/AArch64).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr VecS s(uint32_t id) noexcept { return VecS(id); }
|
||||
//! Creates a 64-bit D register operand (ARM/AArch64).
|
||||
@@ -385,23 +342,18 @@ public:
|
||||
kSignatureMemShiftValueShift = 14,
|
||||
kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
|
||||
|
||||
// Shift operation type (4 bits).
|
||||
// Index shift operation (4 bits).
|
||||
// |........|XXXX....|........|........|
|
||||
kSignatureMemPredicateShift = 20,
|
||||
kSignatureMemPredicateMask = 0x0Fu << kSignatureMemPredicateShift
|
||||
kSignatureMemShiftOpShift = 20,
|
||||
kSignatureMemShiftOpMask = 0x0Fu << kSignatureMemShiftOpShift,
|
||||
|
||||
// Offset mode type (2 bits).
|
||||
// |......XX|........|........|........|
|
||||
kSignatureMemOffsetModeShift = 24,
|
||||
kSignatureMemOffsetModeMask = 0x03u << kSignatureMemOffsetModeShift
|
||||
};
|
||||
//! \endcond
|
||||
|
||||
//! Memory offset mode.
|
||||
//!
|
||||
//! Additional constants that can be used with the `predicate`.
|
||||
enum OffsetMode : uint32_t {
|
||||
//! Pre-index "[BASE, #Offset {, <shift>}]!" with write-back.
|
||||
kOffsetPreIndex = 0xE,
|
||||
//! Post-index "[BASE], #Offset {, <shift>}" with write-back.
|
||||
kOffsetPostIndex = 0xF
|
||||
};
|
||||
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
|
||||
@@ -438,7 +390,7 @@ public:
|
||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
||||
Signature::fromMemBaseType(base.type()) |
|
||||
Signature::fromMemIndexType(index.type()) |
|
||||
Signature::fromValue<kSignatureMemPredicateMask>(uint32_t(shift.op())) |
|
||||
Signature::fromValue<kSignatureMemShiftOpMask>(uint32_t(shift.op())) |
|
||||
Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
|
||||
signature, base.id(), index.id(), 0) {}
|
||||
|
||||
@@ -471,14 +423,14 @@ public:
|
||||
//! Clones the memory operand and makes it pre-index.
|
||||
ASMJIT_INLINE_NODEBUG Mem pre() const noexcept {
|
||||
Mem result(*this);
|
||||
result.setPredicate(kOffsetPreIndex);
|
||||
result.setOffsetMode(OffsetMode::kPreIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Clones the memory operand, applies a given offset `off` and makes it pre-index.
|
||||
ASMJIT_INLINE_NODEBUG Mem pre(int64_t off) const noexcept {
|
||||
Mem result(*this);
|
||||
result.setPredicate(kOffsetPreIndex);
|
||||
result.setOffsetMode(OffsetMode::kPreIndex);
|
||||
result.addOffset(off);
|
||||
return result;
|
||||
}
|
||||
@@ -486,14 +438,14 @@ public:
|
||||
//! Clones the memory operand and makes it post-index.
|
||||
ASMJIT_INLINE_NODEBUG Mem post() const noexcept {
|
||||
Mem result(*this);
|
||||
result.setPredicate(kOffsetPostIndex);
|
||||
result.setOffsetMode(OffsetMode::kPostIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Clones the memory operand, applies a given offset `off` and makes it post-index.
|
||||
ASMJIT_INLINE_NODEBUG Mem post(int64_t off) const noexcept {
|
||||
Mem result(*this);
|
||||
result.setPredicate(kOffsetPostIndex);
|
||||
result.setOffsetMode(OffsetMode::kPostIndex);
|
||||
result.addOffset(off);
|
||||
return result;
|
||||
}
|
||||
@@ -520,88 +472,85 @@ public:
|
||||
setShift(shift);
|
||||
}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void setIndex(const BaseReg& index, Shift shift) noexcept {
|
||||
setIndex(index);
|
||||
setShift(shift);
|
||||
}
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name ARM Specific Features
|
||||
//! \{
|
||||
|
||||
//! Gets offset mode.
|
||||
ASMJIT_INLINE_NODEBUG constexpr OffsetMode offsetMode() const noexcept { return OffsetMode(_signature.getField<kSignatureMemOffsetModeMask>()); }
|
||||
//! Sets offset mode to `mode`.
|
||||
ASMJIT_INLINE_NODEBUG void setOffsetMode(OffsetMode mode) noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(mode)); }
|
||||
//! Resets offset mode to default (fixed offset, without write-back).
|
||||
ASMJIT_INLINE_NODEBUG void resetOffsetMode() noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(OffsetMode::kFixed)); }
|
||||
|
||||
//! Tests whether the current memory offset mode is fixed (see \ref OffsetMode::kFixed).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isFixedOffset() const noexcept { return offsetMode() == OffsetMode::kFixed; }
|
||||
//! Tests whether the current memory offset mode is either pre-index or post-index (write-back is used).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPreOrPost() const noexcept { return offsetMode() != OffsetMode::kFixed; }
|
||||
//! Tests whether the current memory offset mode is pre-index (write-back is used).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPreIndex() const noexcept { return offsetMode() == OffsetMode::kPreIndex; }
|
||||
//! Tests whether the current memory offset mode is post-index (write-back is used).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPostIndex() const noexcept { return offsetMode() == OffsetMode::kPostIndex; }
|
||||
|
||||
//! Sets offset mode of this memory operand to pre-index (write-back is used).
|
||||
ASMJIT_INLINE_NODEBUG void makePreIndex() noexcept { setOffsetMode(OffsetMode::kPreIndex); }
|
||||
//! Sets offset mode of this memory operand to post-index (write-back is used).
|
||||
ASMJIT_INLINE_NODEBUG void makePostIndex() noexcept { setOffsetMode(OffsetMode::kPostIndex); }
|
||||
|
||||
//! Gets shift operation that is used by index register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr ShiftOp shiftOp() const noexcept { return ShiftOp(_signature.getField<kSignatureMemShiftOpMask>()); }
|
||||
//! Sets shift operation that is used by index register.
|
||||
ASMJIT_INLINE_NODEBUG void setShiftOp(ShiftOp sop) noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(sop)); }
|
||||
//! Resets shift operation that is used by index register to LSL (default value).
|
||||
ASMJIT_INLINE_NODEBUG void resetShiftOp() noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(ShiftOp::kLSL)); }
|
||||
|
||||
//! Gets whether the memory operand has shift (aka scale) constant.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
|
||||
//! Gets the memory operand's shift (aka scale) constant.
|
||||
ASMJIT_INLINE_NODEBUG constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
|
||||
//! Sets the memory operand's shift (aka scale) constant.
|
||||
ASMJIT_INLINE_NODEBUG void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
|
||||
|
||||
//! Sets the memory operand's shift and shift operation.
|
||||
ASMJIT_INLINE_NODEBUG void setShift(Shift shift) noexcept {
|
||||
_signature.setField<kSignatureMemShiftOpMask>(uint32_t(shift.op()));
|
||||
_signature.setField<kSignatureMemShiftValueMask>(shift.value());
|
||||
}
|
||||
|
||||
//! Resets the memory operand's shift (aka scale) constant to zero.
|
||||
ASMJIT_INLINE_NODEBUG void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
|
||||
|
||||
//! Gets memory predicate (shift mode or offset mode), see \ref ShiftOp and \ref OffsetMode.
|
||||
ASMJIT_INLINE_NODEBUG constexpr uint32_t predicate() const noexcept { return _signature.getField<kSignatureMemPredicateMask>(); }
|
||||
//! Sets memory predicate to `predicate`, see `Mem::ShiftOp`.
|
||||
ASMJIT_INLINE_NODEBUG void setPredicate(uint32_t predicate) noexcept { _signature.setField<kSignatureMemPredicateMask>(predicate); }
|
||||
//! Resets shift mode to LSL (default).
|
||||
ASMJIT_INLINE_NODEBUG void resetPredicate() noexcept { _signature.setField<kSignatureMemPredicateMask>(0); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isFixedOffset() const noexcept { return predicate() < kOffsetPreIndex; }
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPreOrPost() const noexcept { return predicate() >= kOffsetPreIndex; }
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPreIndex() const noexcept { return predicate() == kOffsetPreIndex; }
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPostIndex() const noexcept { return predicate() == kOffsetPostIndex; }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void resetToFixedOffset() noexcept { resetPredicate(); }
|
||||
ASMJIT_INLINE_NODEBUG void makePreIndex() noexcept { setPredicate(kOffsetPreIndex); }
|
||||
ASMJIT_INLINE_NODEBUG void makePostIndex() noexcept { setPredicate(kOffsetPostIndex); }
|
||||
|
||||
//! \}
|
||||
};
|
||||
|
||||
//! Creates `[base, offset]` memory operand (offset mode).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset);
|
||||
}
|
||||
//! \name Shift Operation Construction
|
||||
//! \{
|
||||
|
||||
//! Creates `[base, offset]!` memory operand (pre-index mode).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPreIndex));
|
||||
}
|
||||
//! Constructs a `LSL #value` shift (logical shift left).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
|
||||
//! Constructs a `LSR #value` shift (logical shift right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
|
||||
//! Constructs a `ASR #value` shift (arithmetic shift right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
|
||||
//! Constructs a `ROR #value` shift (rotate right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
|
||||
//! Constructs a `RRX` shift (rotate with carry by 1).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift rrx() noexcept { return Shift(ShiftOp::kRRX, 0); }
|
||||
//! Constructs a `MSL #value` shift (logical shift left filling ones).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift msl(uint32_t value) noexcept { return Shift(ShiftOp::kMSL, value); }
|
||||
|
||||
//! Creates `[base], offset` memory operand (post-index mode).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
|
||||
}
|
||||
//! \}
|
||||
|
||||
//! Creates `[base, index]` memory operand.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, const Gp& index) noexcept {
|
||||
return Mem(base, index);
|
||||
}
|
||||
//! \name Memory Operand Construction
|
||||
//! \{
|
||||
|
||||
//! Creates `[base, index]!` memory operand (pre-index mode).
|
||||
static ASMJIT_INLINE_NODEBUG 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 ASMJIT_INLINE_NODEBUG constexpr Mem ptr_post(const Gp& base, const Gp& index) noexcept {
|
||||
return Mem(base, index, OperandSignature::fromValue<Mem::kSignatureMemPredicateMask>(Mem::kOffsetPostIndex));
|
||||
}
|
||||
|
||||
//! Creates `[base, index, SHIFT_OP #shift]` memory operand.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
|
||||
return Mem(base, index, shift);
|
||||
}
|
||||
|
||||
//! Creates `[base, offset]` memory operand.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const Label& base, int32_t offset = 0) noexcept {
|
||||
return Mem(base, offset);
|
||||
}
|
||||
|
||||
// TODO: [ARM] PC + offset address.
|
||||
#if 0
|
||||
//! Creates `[PC + offset]` (relative) memory operand.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(const PC& pc, int32_t offset = 0) noexcept {
|
||||
return Mem(pc, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Creates `[base]` absolute memory operand.
|
||||
//! Creates `[base]` absolute memory operand (AArch32 or AArch64).
|
||||
//!
|
||||
//! \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
|
||||
@@ -611,12 +560,12 @@ static ASMJIT_INLINE_NODEBUG constexpr Mem ptr(uint64_t base) noexcept { return
|
||||
|
||||
//! \}
|
||||
|
||||
//! \}
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
//! \cond INTERNAL
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
ASMJIT_DEFINE_TYPE_ID(arm::GpW, TypeId::kInt32);
|
||||
ASMJIT_DEFINE_TYPE_ID(arm::GpX, TypeId::kInt64);
|
||||
ASMJIT_DEFINE_TYPE_ID(arm::VecS, TypeId::kFloat32x1);
|
||||
ASMJIT_DEFINE_TYPE_ID(arm::VecD, TypeId::kFloat64x1);
|
||||
ASMJIT_DEFINE_TYPE_ID(arm::VecV, TypeId::kInt32x4);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef ASMJIT_ARM_ARMUTILS_H_INCLUDED
|
||||
#define ASMJIT_ARM_ARMUTILS_H_INCLUDED
|
||||
|
||||
#include "../core/support.h"
|
||||
#include "../arm/armglobals.h"
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
||||
@@ -16,6 +17,38 @@ ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
||||
//! Public utilities and helpers for targeting AArch32 and AArch64 architectures.
|
||||
namespace Utils {
|
||||
|
||||
//! Encodes a 12-bit immediate part of opcode that ise used by a standard 32-bit ARM encoding.
|
||||
ASMJIT_MAYBE_UNUSED
|
||||
static inline bool encodeAArch32Imm(uint64_t imm, uint32_t* encodedImmOut) noexcept {
|
||||
if (imm & 0xFFFFFFFF00000000u)
|
||||
return false;
|
||||
|
||||
uint32_t v = uint32_t(imm);
|
||||
uint32_t r = 0;
|
||||
|
||||
if (v <= 0xFFu) {
|
||||
*encodedImmOut = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rotate if there are bits on both ends (LSB and MSB)
|
||||
// (otherwise we would not be able to calculate the rotation with ctz).
|
||||
if (v & 0xFF0000FFu) {
|
||||
v = Support::ror(v, 16);
|
||||
r = 16u;
|
||||
}
|
||||
|
||||
uint32_t n = Support::ctz(v) & ~0x1u;
|
||||
r = (r - n) & 0x1Eu;
|
||||
v = Support::ror(v, n);
|
||||
|
||||
if (v > 0xFFu)
|
||||
return false;
|
||||
|
||||
*encodedImmOut = v | (r << 7);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Decomposed fields of a logical immediate value.
|
||||
struct LogicalImm {
|
||||
uint32_t n;
|
||||
|
||||
@@ -1624,7 +1624,7 @@ namespace asmjit {
|
||||
//!
|
||||
//! Each instruction can be then queried for the following information:
|
||||
//!
|
||||
//! - \ref InstRWInfo - Read/write information of instruction and its oprands (includes \ref OpRWInfo).
|
||||
//! - \ref InstRWInfo - Read/write information of instruction and its operands (includes \ref OpRWInfo).
|
||||
//!
|
||||
//! - \ref CpuFeatures - CPU features required to execute the instruction.
|
||||
//!
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
@@ -112,7 +113,7 @@ namespace asmjit {
|
||||
#define ASMJIT_NO_INTROSPECTION
|
||||
|
||||
// Avoid doxygen preprocessor using feature-selection definitions.
|
||||
#undef ASMJIT_BUILD_EMBNED
|
||||
#undef ASMJIT_BUILD_EMBED
|
||||
#undef ASMJIT_BUILD_STATIC
|
||||
#undef ASMJIT_BUILD_DEBUG
|
||||
#undef ASMJIT_BUILD_RELEASE
|
||||
@@ -212,7 +213,7 @@ namespace asmjit {
|
||||
#define ASMJIT_NO_X86
|
||||
#endif
|
||||
|
||||
#if !ASMJIT_ARCH_ARM && !defined(ASMJIT_NO_AARCH64)
|
||||
#if ASMJIT_ARCH_ARM != 64 && !defined(ASMJIT_NO_AARCH64)
|
||||
#define ASMJIT_NO_AARCH64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -29,8 +29,8 @@ enum class CondCode : uint8_t {
|
||||
kNE = 0x03u, //!< Z==0 (any_sign !=)
|
||||
kCS = 0x04u, //!< C==1 (unsigned >=)
|
||||
kHS = 0x04u, //!< C==1 (unsigned >=)
|
||||
kCC = 0x05u, //!< C==0 (unsigned < )
|
||||
kLO = 0x05u, //!< C==0 (unsigned < )
|
||||
kCC = 0x05u, //!< C==0 (unsigned < )
|
||||
kMI = 0x06u, //!< N==1 (is negative)
|
||||
kPL = 0x07u, //!< N==0 (is positive or zero)
|
||||
kVS = 0x08u, //!< V==1 (is overflow)
|
||||
@@ -75,41 +75,16 @@ enum class CondCode : uint8_t {
|
||||
//! Negates a condition code.
|
||||
static ASMJIT_INLINE_NODEBUG constexpr CondCode negateCond(CondCode cond) noexcept { return CondCode(uint8_t(cond) ^ uint8_t(1)); }
|
||||
|
||||
//! Data type that can be encoded with the instruction (AArch32 only).
|
||||
enum class DataType : uint32_t {
|
||||
//! No data type specified (default for all general purpose instructions).
|
||||
kNone = 0,
|
||||
//! 8-bit signed integer, specified as `.s8` in assembly.
|
||||
kS8 = 1,
|
||||
//! 16-bit signed integer, specified as `.s16` in assembly.
|
||||
kS16 = 2,
|
||||
//! 32-bit signed integer, specified as `.s32` in assembly.
|
||||
kS32 = 3,
|
||||
//! 64-bit signed integer, specified as `.s64` in assembly.
|
||||
kS64 = 4,
|
||||
//! 8-bit unsigned integer, specified as `.u8` in assembly.
|
||||
kU8 = 5,
|
||||
//! 16-bit unsigned integer, specified as `.u16` in assembly.
|
||||
kU16 = 6,
|
||||
//! 32-bit unsigned integer, specified as `.u32` in assembly.
|
||||
kU32 = 7,
|
||||
//! 64-bit unsigned integer, specified as `.u64` in assembly.
|
||||
kU64 = 8,
|
||||
//! 16-bit floating point (half precision), specified as `.f16` in assembly.
|
||||
kF16 = 10,
|
||||
//! 32-bit floating point (single precision), specified as `.f32` in assembly.
|
||||
kF32 = 11,
|
||||
//! 64-bit floating point (double precision), specified as `.f64` in assembly.
|
||||
kF64 = 12,
|
||||
//! 8-bit polynomial.
|
||||
kP8 = 13,
|
||||
//! 16-bit BF16 floating point.
|
||||
kBF16 = 14,
|
||||
//! 64-bit polynomial.
|
||||
kP64 = 15,
|
||||
|
||||
//! Maximum value of `DataType`.
|
||||
kMaxValue = 15
|
||||
//! Memory offset mode.
|
||||
//!
|
||||
//! Describes either fixed, pre-index, or post-index offset modes.
|
||||
enum class OffsetMode : uint32_t {
|
||||
//! Fixed offset mode (either no index at all or a regular index without a write-back).
|
||||
kFixed = 0u,
|
||||
//! Pre-index "[BASE, #Offset {, <shift>}]!" with write-back.
|
||||
kPreIndex = 1u,
|
||||
//! Post-index "[BASE], #Offset {, <shift>}" with write-back.
|
||||
kPostIndex = 2u
|
||||
};
|
||||
|
||||
//! Shift operation predicate (ARM) describes either SHIFT or EXTEND operation.
|
||||
@@ -187,45 +162,70 @@ public:
|
||||
//! Sets shift operation to `op`.
|
||||
ASMJIT_INLINE_NODEBUG void setOp(ShiftOp op) noexcept { _op = op; }
|
||||
|
||||
//! Returns the shift smount.
|
||||
//! Returns the shift amount.
|
||||
ASMJIT_INLINE_NODEBUG constexpr uint32_t value() const noexcept { return _value; }
|
||||
//! Sets shift amount to `value`.
|
||||
ASMJIT_INLINE_NODEBUG void setValue(uint32_t value) noexcept { _value = value; }
|
||||
};
|
||||
|
||||
//! Constructs a `LSL #value` shift (logical shift left).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
|
||||
//! Constructs a `LSR #value` shift (logical shift right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
|
||||
//! Constructs a `ASR #value` shift (arithmetic shift right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
|
||||
//! Constructs a `ROR #value` shift (rotate right).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
|
||||
//! Constructs a `RRX` shift (rotate with carry by 1).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift rrx() noexcept { return Shift(ShiftOp::kRRX, 0); }
|
||||
//! Constructs a `MSL #value` shift (logical shift left filling ones).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift msl(uint32_t value) noexcept { return Shift(ShiftOp::kMSL, value); }
|
||||
|
||||
//! Constructs a `UXTB #value` extend and shift (unsigned byte extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtb(uint32_t value) noexcept { return Shift(ShiftOp::kUXTB, value); }
|
||||
//! Constructs a `UXTH #value` extend and shift (unsigned hword extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxth(uint32_t value) noexcept { return Shift(ShiftOp::kUXTH, value); }
|
||||
//! Constructs a `UXTW #value` extend and shift (unsigned word extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtw(uint32_t value) noexcept { return Shift(ShiftOp::kUXTW, value); }
|
||||
//! Constructs a `UXTX #value` extend and shift (unsigned dword extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift uxtx(uint32_t value) noexcept { return Shift(ShiftOp::kUXTX, value); }
|
||||
|
||||
//! Constructs a `SXTB #value` extend and shift (signed byte extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtb(uint32_t value) noexcept { return Shift(ShiftOp::kSXTB, value); }
|
||||
//! Constructs a `SXTH #value` extend and shift (signed hword extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxth(uint32_t value) noexcept { return Shift(ShiftOp::kSXTH, value); }
|
||||
//! Constructs a `SXTW #value` extend and shift (signed word extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtw(uint32_t value) noexcept { return Shift(ShiftOp::kSXTW, value); }
|
||||
//! Constructs a `SXTX #value` extend and shift (signed dword extend).
|
||||
static ASMJIT_INLINE_NODEBUG constexpr Shift sxtx(uint32_t value) noexcept { return Shift(ShiftOp::kSXTX, value); }
|
||||
|
||||
//! \}
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
|
||||
|
||||
using namespace arm;
|
||||
|
||||
//! Data type that can be encoded with AArch32 instruction identifier.
|
||||
//!
|
||||
//! \note Data types are frequently used with AArch32 SIMD instructions. For example `VMAX` instruction can
|
||||
//! use almost all datatypes in a form `VMAX.F32`, `VMAX.S16`, `VMAX.U32`, etc... Emitter automatically adds
|
||||
//! the required data type at emit level.
|
||||
enum class DataType : uint32_t {
|
||||
//! No data type specified (default for all general purpose instructions).
|
||||
kNone = 0,
|
||||
//! 8-bit signed integer, specified as `.s8` in assembly.
|
||||
kS8 = 1,
|
||||
//! 16-bit signed integer, specified as `.s16` in assembly.
|
||||
kS16 = 2,
|
||||
//! 32-bit signed integer, specified as `.s32` in assembly.
|
||||
kS32 = 3,
|
||||
//! 64-bit signed integer, specified as `.s64` in assembly.
|
||||
kS64 = 4,
|
||||
//! 8-bit unsigned integer, specified as `.u8` in assembly.
|
||||
kU8 = 5,
|
||||
//! 16-bit unsigned integer, specified as `.u16` in assembly.
|
||||
kU16 = 6,
|
||||
//! 32-bit unsigned integer, specified as `.u32` in assembly.
|
||||
kU32 = 7,
|
||||
//! 64-bit unsigned integer, specified as `.u64` in assembly.
|
||||
kU64 = 8,
|
||||
//! 16-bit floating point (half precision), specified as `.f16` in assembly.
|
||||
kF16 = 10,
|
||||
//! 32-bit floating point (single precision), specified as `.f32` in assembly.
|
||||
kF32 = 11,
|
||||
//! 64-bit floating point (double precision), specified as `.f64` in assembly.
|
||||
kF64 = 12,
|
||||
//! 8-bit polynomial.
|
||||
kP8 = 13,
|
||||
//! 16-bit BF16 floating point.
|
||||
kBF16 = 14,
|
||||
//! 64-bit polynomial.
|
||||
kP64 = 15,
|
||||
|
||||
//! Maximum value of `DataType`.
|
||||
kMaxValue = 15
|
||||
};
|
||||
|
||||
static ASMJIT_INLINE_NODEBUG uint32_t dataTypeSize(DataType dt) noexcept {
|
||||
static constexpr uint8_t table[] = { 0, 1, 2, 4, 8, 1, 2, 4, 8, 2, 4, 8, 1, 2, 8 };
|
||||
return table[size_t(dt)];
|
||||
}
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
using namespace arm;
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
#endif // ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
||||
|
||||
@@ -590,7 +590,7 @@ Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1,
|
||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||
|
||||
ValidationFlags validationFlags = isCompiler() ? ValidationFlags::kEnableVirtRegs : ValidationFlags::kNone;
|
||||
Error err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount, validationFlags);
|
||||
Error err = _funcs.validate(BaseInst(instId, options, _extraReg), opArray, opCount, validationFlags);
|
||||
|
||||
if (ASMJIT_UNLIKELY(err)) {
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
|
||||
@@ -45,7 +45,7 @@ enum class ExpressionOpType : uint8_t {
|
||||
kSra = 5
|
||||
};
|
||||
|
||||
//! Value tyoe that can be used within an \ref Expression.
|
||||
//! Value type that can be used within an \ref Expression.
|
||||
enum class ExpressionValueType : uint8_t {
|
||||
//! No value or invalid.
|
||||
kNone = 0,
|
||||
@@ -272,6 +272,9 @@ public:
|
||||
|
||||
//! Offset format type, used by \ref OffsetFormat.
|
||||
enum class OffsetType : uint8_t {
|
||||
// Common Offset Formats
|
||||
// ---------------------
|
||||
|
||||
//! A value having `_immBitCount` bits and shifted by `_immBitShift`.
|
||||
//!
|
||||
//! This offset type is sufficient for many targets that store offset as a continuous set bits within an
|
||||
@@ -284,14 +287,82 @@ enum class OffsetType : uint8_t {
|
||||
// AArch64 Specific Offset Formats
|
||||
// -------------------------------
|
||||
|
||||
//! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
|
||||
//! AArch64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
|
||||
kAArch64_ADR,
|
||||
|
||||
//! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
|
||||
//! AArch64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
|
||||
kAArch64_ADRP,
|
||||
|
||||
// AArch32 Specific Offset Formats (T16 & T32)
|
||||
// -------------------------------------------
|
||||
|
||||
//! AArch32 THUMBv2 immediate encoding of 'ADR' instruction (12-bit payload and sign bit):
|
||||
//!
|
||||
//! `|.....|imm:1|..N.N|......|imm:3|....|imm:8|`
|
||||
//!
|
||||
//! Where `N` is one if the offset is negative. The immediate is encoded as absolute value of the offset if negative.
|
||||
kThumb32_ADR,
|
||||
|
||||
//! AArch32 THUMBv2 immediate encoding of 'BLX' instruction (23-bit immediate payload, multiplied by 4):
|
||||
//!
|
||||
//! `|.....|imm[22]|imm[19:10]|..|ja|1|jb|imm[9:0]|0`
|
||||
//!
|
||||
//! Where:
|
||||
//!
|
||||
//! - `ja` is calculated as imm[22] ^ imm[21] ^ 1.
|
||||
//! - `jb` is calculated as imm[22] ^ imm[20] ^ 1.
|
||||
kThumb32_BLX,
|
||||
|
||||
//! AArch32 THUMBv2 immediate encoding of 'B' instruction without <cond> (24-bit immediate payload, multiplied by 2):
|
||||
//!
|
||||
//! `|.....|imm[23]|imm[20:11]|..|ja|1|jb|imm[10:0]`
|
||||
//!
|
||||
//! Where:
|
||||
//!
|
||||
//! - `ja` is calculated as imm[23] ^ imm[22] ^ 1.
|
||||
//! - `jb` is calculated as imm[23] ^ imm[21] ^ 1.
|
||||
kThumb32_B,
|
||||
|
||||
//! AArch32 THUMBv2 immediate encoding of 'B' instruction with <cond> (20-bit immediate payload, multiplied by 2).
|
||||
//!
|
||||
//! `|.....|imm[19]|....|imm[16:11]|..|ja|1|jb|imm[10:0]`
|
||||
//!
|
||||
//! Where:
|
||||
//!
|
||||
//! - `ja` is calculated as imm[19] ^ imm[18] ^ 1.
|
||||
//! - `jb` is calculated as imm[19] ^ imm[17] ^ 1.
|
||||
kThumb32_BCond,
|
||||
|
||||
// AArch32 Specific Offset Formats (A32)
|
||||
// -------------------------------------
|
||||
|
||||
//! AArch32 ADR instruction, which uses a standard 12-bit immediate encoding that is used by other ARM instructions.
|
||||
kAArch32_ADR,
|
||||
|
||||
//! AArch32 signed offset that is similar to `kSignedOffset`, however it uses absolute value of the offset and its
|
||||
//! sign is encoded in 23rd bit of the opcode.
|
||||
//!
|
||||
//! `|........|U.......|........|........|`
|
||||
//!
|
||||
kAArch32_U23_SignedOffset,
|
||||
|
||||
//! AArch32 offset format that encodes 8-bit offset as:
|
||||
//!
|
||||
//! `|........|U.......|....|imm[7:4]|....|imm[3:0]|`
|
||||
//!
|
||||
//! in a 32-bit word, where U is a sign of the displacement and the displacement itself is encoded as its absolute
|
||||
//! value.
|
||||
kAArch32_U23_0To3At0_4To7At8,
|
||||
|
||||
//! AArch32 offset format that encodes a signed 25-bit offset as:
|
||||
//!
|
||||
//! `|.......|imm[0]|imm[24:1]|`
|
||||
//!
|
||||
//! in a 32-bit word.
|
||||
kAArch32_1To24At0_0At24,
|
||||
|
||||
//! Maximum value of `OffsetFormatType`.
|
||||
kMaxValue = kAArch64_ADRP
|
||||
kMaxValue = kAArch32_1To24At0_0At24
|
||||
};
|
||||
|
||||
//! Provides information about formatting offsets, absolute addresses, or their parts. Offset format is used by both
|
||||
@@ -350,15 +421,24 @@ struct OffsetFormat {
|
||||
//! Returns the type of the offset.
|
||||
ASMJIT_INLINE_NODEBUG OffsetType type() const noexcept { return _type; }
|
||||
|
||||
//! Returns whether the offset is encoded as an absolute value of the offset with additional field(s) that represent
|
||||
//! the sign (AArch32 U/N fields in the opcode).
|
||||
//!
|
||||
//! If true, the offset itself is always positive and a separate U/N field is used to indicate the sign of the offset
|
||||
//! (usually `U==1` means ADD, but sometimes `N==1` means negative offset, which implies SUB).
|
||||
ASMJIT_INLINE_NODEBUG bool hasSignBit() const noexcept {
|
||||
return _type == OffsetType::kThumb32_ADR ||
|
||||
_type == OffsetType::kAArch32_ADR ||
|
||||
_type == OffsetType::kAArch32_U23_SignedOffset ||
|
||||
_type == OffsetType::kAArch32_U23_0To3At0_4To7At8;
|
||||
}
|
||||
|
||||
//! Returns flags.
|
||||
ASMJIT_INLINE_NODEBUG uint32_t flags() const noexcept { return _flags; }
|
||||
|
||||
//! Returns the size of the region/instruction where the offset is encoded.
|
||||
ASMJIT_INLINE_NODEBUG uint32_t regionSize() const noexcept { return _regionSize; }
|
||||
|
||||
//! Returns the offset of the word relative to the start of the region where the offset is.
|
||||
ASMJIT_INLINE_NODEBUG uint32_t valueOffset() const noexcept { return _valueOffset; }
|
||||
|
||||
//! Returns the size of the data-type (word) that contains the offset, in bytes.
|
||||
ASMJIT_INLINE_NODEBUG uint32_t valueSize() const noexcept { return _valueSize; }
|
||||
//! Returns the count of bits of the offset value in the data it's stored in.
|
||||
@@ -850,7 +930,7 @@ public:
|
||||
//! use the same slot.
|
||||
//!
|
||||
//! This function should be considered internal as it's used by assemblers to insert an absolute address into the
|
||||
//! address table. Inserting address into address table without creating a particula relocation entry makes no sense.
|
||||
//! address table. Inserting address into address table without creating a particular relocation entry makes no sense.
|
||||
ASMJIT_API Error addAddressToAddressTable(uint64_t address) noexcept;
|
||||
|
||||
//! \}
|
||||
@@ -1018,7 +1098,8 @@ public:
|
||||
//! Relocates the code to the given `baseAddress`.
|
||||
//!
|
||||
//! \param baseAddress Absolute base address where the code will be relocated to. Please note that nothing is
|
||||
//! copied to such base address, it's just an absolute value used by the relocator to resolve all stored relocations.
|
||||
//! copied to such base address, it's just an absolute value used by the relocation code to resolve all stored
|
||||
//! relocations.
|
||||
//!
|
||||
//! \note This should never be called more than once.
|
||||
ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "../core/api-build_p.h"
|
||||
#include "../core/codeholder.h"
|
||||
#include "../core/codewriter_p.h"
|
||||
#include "../arm/armutils.h"
|
||||
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
@@ -19,9 +20,20 @@ bool CodeWriterUtils::encodeOffset32(uint32_t* dst, int64_t offset64, const Offs
|
||||
return false;
|
||||
|
||||
uint32_t value;
|
||||
uint32_t u = 0;
|
||||
bool unsignedLogic = format.type() == OffsetType::kUnsignedOffset;
|
||||
|
||||
// First handle all offsets that use additional field for their sign and the offset is encoded as its
|
||||
// absolute value.
|
||||
if (format.hasSignBit()) {
|
||||
u = uint32_t(offset64 >= 0);
|
||||
if (u == 0)
|
||||
offset64 = -offset64;
|
||||
unsignedLogic = true;
|
||||
}
|
||||
|
||||
// First handle all unsigned offset types.
|
||||
if (format.type() == OffsetType::kUnsignedOffset) {
|
||||
if (unsignedLogic) {
|
||||
if (discardLsb) {
|
||||
ASMJIT_ASSERT(discardLsb <= 32);
|
||||
if ((offset64 & Support::lsbMask<uint32_t>(discardLsb)) != 0)
|
||||
@@ -57,6 +69,97 @@ bool CodeWriterUtils::encodeOffset32(uint32_t* dst, int64_t offset64, const Offs
|
||||
return true;
|
||||
}
|
||||
|
||||
// Opcode: {.....|imm:1|..N.N|......|imm:3|....|imm:8}
|
||||
case OffsetType::kThumb32_ADR: {
|
||||
// Sanity checks.
|
||||
if (format.valueSize() != 4 || bitCount != 12 || bitShift != 0)
|
||||
return false;
|
||||
|
||||
uint32_t imm8 = (value & 0x00FFu);
|
||||
uint32_t imm3 = (value & 0x0700u) << (12 - 8);
|
||||
uint32_t imm1 = (value & 0x0800u) << (26 - 11);
|
||||
uint32_t n = u ^ 1u;
|
||||
|
||||
*dst = imm8 | imm3 | imm1 | (n << 21) | (n << 23);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Opcode: {....|.|imm[22]|imm[19:10]|..|ja|.|jb|imm[9:0]|.}
|
||||
case OffsetType::kThumb32_BLX:
|
||||
// The calculation is the same as `B`, but the first LSB bit must be zero, so account for that.
|
||||
value <<= 1;
|
||||
ASMJIT_FALLTHROUGH;
|
||||
|
||||
// Opcode: {....|.|imm[23]|imm[20:11]|..|ja|.|jb|imm[10:0]}
|
||||
case OffsetType::kThumb32_B: {
|
||||
// Sanity checks.
|
||||
if (format.valueSize() != 4)
|
||||
return false;
|
||||
|
||||
uint32_t ia = (value & 0x0007FFu);
|
||||
uint32_t ib = (value & 0x1FF800u) << (16 - 11);
|
||||
uint32_t ic = (value & 0x800000u) << (26 - 23);
|
||||
uint32_t ja = ((~value >> 23) ^ (value >> 22)) & 1u;
|
||||
uint32_t jb = ((~value >> 23) ^ (value >> 21)) & 1u;
|
||||
|
||||
*dst = ia | ib | ic | (ja << 14) | (jb << 11);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Opcode: {....|.|imm[19]|....|imm[16:11]|..|ja|.|jb|imm[10:0]}
|
||||
case OffsetType::kThumb32_BCond: {
|
||||
// Sanity checks.
|
||||
if (format.valueSize() != 4 || bitCount != 20 || bitShift != 0)
|
||||
return false;
|
||||
|
||||
uint32_t ia = (value & 0x0007FFu);
|
||||
uint32_t ib = (value & 0x01F800u) << (16 - 11);
|
||||
uint32_t ic = (value & 0x080000u) << (26 - 19);
|
||||
uint32_t ja = ((~value >> 19) ^ (value >> 22)) & 1u;
|
||||
uint32_t jb = ((~value >> 19) ^ (value >> 21)) & 1u;
|
||||
|
||||
*dst = ia | ib | ic | (ja << 14) | (jb << 11);
|
||||
return true;
|
||||
}
|
||||
|
||||
case OffsetType::kAArch32_ADR: {
|
||||
uint32_t encodedImm;
|
||||
if (!arm::Utils::encodeAArch32Imm(value, &encodedImm))
|
||||
return false;
|
||||
|
||||
*dst = (Support::bitMask(22) << u) | (encodedImm << bitShift);
|
||||
return true;
|
||||
}
|
||||
|
||||
case OffsetType::kAArch32_U23_SignedOffset: {
|
||||
*dst = (value << bitShift) | (u << 23);
|
||||
return true;
|
||||
}
|
||||
|
||||
case OffsetType::kAArch32_U23_0To3At0_4To7At8: {
|
||||
// Sanity checks.
|
||||
if (format.valueSize() != 4 || bitCount != 8 || bitShift != 0)
|
||||
return false;
|
||||
|
||||
uint32_t immLo = (value & 0x0Fu);
|
||||
uint32_t immHi = (value & 0xF0u) << (8 - 4);
|
||||
|
||||
*dst = immLo | immHi | (u << 23);
|
||||
return true;
|
||||
}
|
||||
|
||||
case OffsetType::kAArch32_1To24At0_0At24: {
|
||||
// Sanity checks.
|
||||
if (format.valueSize() != 4 || bitCount != 25 || bitShift != 0)
|
||||
return false;
|
||||
|
||||
uint32_t immLo = (value & 0x0000001u) << 24;
|
||||
uint32_t immHi = (value & 0x1FFFFFEu) >> 1;
|
||||
|
||||
*dst = immLo | immHi;
|
||||
return true;
|
||||
}
|
||||
|
||||
case OffsetType::kAArch64_ADR:
|
||||
case OffsetType::kAArch64_ADRP: {
|
||||
// Sanity checks.
|
||||
|
||||
@@ -693,7 +693,7 @@ static ASMJIT_FAVOR_SIZE void populateARMv8AFeatures(CpuFeatures::ARM& features,
|
||||
features.add(Ext::kCCIDX, Ext::kFCMA, Ext::kJSCVT, Ext::kLRCPC, Ext::kPAUTH);
|
||||
ASMJIT_FALLTHROUGH;
|
||||
case 2: // ARMv8.2
|
||||
features.add(Ext::kCRC32, Ext::kDPB, Ext::kPAN2, Ext::kRAS, Ext::kUAO);
|
||||
features.add(Ext::kDPB, Ext::kPAN2, Ext::kRAS, Ext::kUAO);
|
||||
ASMJIT_FALLTHROUGH;
|
||||
case 1: // ARMv8.1
|
||||
features.add(Ext::kCRC32, Ext::kLOR, Ext::kLSE, Ext::kPAN, Ext::kRDM, Ext::kVHE);
|
||||
@@ -1499,7 +1499,7 @@ static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
||||
|
||||
#ifndef AT_HWCAP
|
||||
#define AT_HWCAP 16
|
||||
#endif // AT_HWCAP
|
||||
#endif // !AT_HWCAP
|
||||
|
||||
#ifndef AT_HWCAP2
|
||||
#define AT_HWCAP2 26
|
||||
|
||||
@@ -384,6 +384,7 @@ Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
|
||||
_errorHandler = nullptr;
|
||||
|
||||
_clearEmitterFlags(~kEmitterPreservedFlags);
|
||||
_instructionAlignment = uint8_t(0);
|
||||
_forcedInstOptions = InstOptions::kReserved;
|
||||
_privateData = 0;
|
||||
|
||||
@@ -393,6 +394,7 @@ Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
|
||||
_instOptions = InstOptions::kNone;
|
||||
_extraReg.reset();
|
||||
_inlineComment = nullptr;
|
||||
_funcs.reset();
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,11 @@ public:
|
||||
EmitterType _emitterType = EmitterType::kNone;
|
||||
//! See \ref EmitterFlags.
|
||||
EmitterFlags _emitterFlags = EmitterFlags::kNone;
|
||||
//! Instruction alignment.
|
||||
uint8_t _instructionAlignment = 0u;
|
||||
//! \cond
|
||||
uint8_t _reservedBaseEmitter = 0u;
|
||||
//! \endcond
|
||||
//! Validation flags in case validation is used.
|
||||
//!
|
||||
//! \note Validation flags are specific to the emitter and they are setup at construction time and then never
|
||||
@@ -263,7 +268,7 @@ public:
|
||||
Arch arch,
|
||||
const BaseInst& inst, const Operand_* operands, size_t opCount) ASMJIT_NOEXCEPT_TYPE;
|
||||
|
||||
typedef Error (ASMJIT_CDECL* ValidateFunc)(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) ASMJIT_NOEXCEPT_TYPE;
|
||||
typedef Error (ASMJIT_CDECL* ValidateFunc)(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) ASMJIT_NOEXCEPT_TYPE;
|
||||
|
||||
//! Emit prolog implementation.
|
||||
EmitProlog emitProlog;
|
||||
@@ -361,6 +366,14 @@ public:
|
||||
//! Returns the target architecture's GP register size (4 or 8 bytes).
|
||||
ASMJIT_INLINE_NODEBUG uint32_t registerSize() const noexcept { return environment().registerSize(); }
|
||||
|
||||
//! Returns instruction alignment.
|
||||
//!
|
||||
//! The following values are returned based on the target architecture:
|
||||
//! - X86 and X86_64 - instruction alignment is 1
|
||||
//! - AArch32 - instruction alignment is 4 in A32 mode and 2 in THUMB mode.
|
||||
//! - AArch64 - instruction alignment is 4
|
||||
ASMJIT_INLINE_NODEBUG uint32_t instructionAlignment() const noexcept { return _instructionAlignment; }
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Initialization & Finalization
|
||||
|
||||
@@ -465,11 +465,6 @@ public:
|
||||
return arch == Arch::kX86 || arch == Arch::kX64;
|
||||
}
|
||||
|
||||
//! Tests whether the given architecture family is ARM, THUMB, or AArch64.
|
||||
static ASMJIT_INLINE_NODEBUG bool isFamilyARM(Arch arch) noexcept {
|
||||
return isArchARM(arch) || isArchAArch64(arch) || isArchThumb(arch);
|
||||
}
|
||||
|
||||
//! Tests whether the given architecture family is AArch32 (ARM or THUMB).
|
||||
static ASMJIT_INLINE_NODEBUG bool isFamilyAArch32(Arch arch) noexcept {
|
||||
return isArchARM(arch) || isArchThumb(arch);
|
||||
@@ -480,6 +475,11 @@ public:
|
||||
return isArchAArch64(arch);
|
||||
}
|
||||
|
||||
//! Tests whether the given architecture family is ARM, THUMB, or AArch64.
|
||||
static ASMJIT_INLINE_NODEBUG bool isFamilyARM(Arch arch) noexcept {
|
||||
return isFamilyAArch32(arch) || isFamilyAArch64(arch);
|
||||
}
|
||||
|
||||
//! Tests whether the given architecture family is MISP or MIPS64.
|
||||
static ASMJIT_INLINE_NODEBUG bool isFamilyMIPS(Arch arch) noexcept {
|
||||
return isArchMIPS32(arch) || isArchMIPS64(arch);
|
||||
|
||||
@@ -166,8 +166,8 @@ Error formatRegister(
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId);
|
||||
if (Environment::isFamilyARM(arch))
|
||||
return arm::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId);
|
||||
#endif
|
||||
|
||||
return kErrorInvalidArch;
|
||||
@@ -186,8 +186,8 @@ Error formatOperand(
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op);
|
||||
if (Environment::isFamilyARM(arch))
|
||||
return arm::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op);
|
||||
#endif
|
||||
|
||||
return kErrorInvalidArch;
|
||||
@@ -284,7 +284,7 @@ Error formatInstruction(
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyARM(arch))
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ ASMJIT_BEGIN_NAMESPACE
|
||||
Error InstAPI::instIdToString(Arch arch, InstId instId, String& output) noexcept {
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
if (Environment::isFamilyX86(arch))
|
||||
return x86::InstInternal::instIdToString(arch, instId, output);
|
||||
return x86::InstInternal::instIdToString(instId, output);
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::InstInternal::instIdToString(arch, instId, output);
|
||||
return a64::InstInternal::instIdToString(instId, output);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
@@ -38,12 +38,12 @@ Error InstAPI::instIdToString(Arch arch, InstId instId, String& output) noexcept
|
||||
InstId InstAPI::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
if (Environment::isFamilyX86(arch))
|
||||
return x86::InstInternal::stringToInstId(arch, s, len);
|
||||
return x86::InstInternal::stringToInstId(s, len);
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::InstInternal::stringToInstId(arch, s, len);
|
||||
return a64::InstInternal::stringToInstId(s, len);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -56,13 +56,17 @@ InstId InstAPI::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
Error InstAPI::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
if (Environment::isFamilyX86(arch))
|
||||
return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags);
|
||||
if (Environment::isFamilyX86(arch)) {
|
||||
if (arch == Arch::kX86)
|
||||
return x86::InstInternal::validateX86(inst, operands, opCount, validationFlags);
|
||||
else
|
||||
return x86::InstInternal::validateX64(inst, operands, opCount, validationFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::InstInternal::validate(arch, inst, operands, opCount, validationFlags);
|
||||
return a64::InstInternal::validate(inst, operands, opCount, validationFlags);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
@@ -84,7 +88,7 @@ Error InstAPI::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* oper
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::InstInternal::queryRWInfo(arch, inst, operands, opCount, out);
|
||||
return a64::InstInternal::queryRWInfo(inst, operands, opCount, out);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
@@ -103,7 +107,7 @@ Error InstAPI::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* op
|
||||
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
if (Environment::isFamilyAArch64(arch))
|
||||
return a64::InstInternal::queryFeatures(arch, inst, operands, opCount, out);
|
||||
return a64::InstInternal::queryFeatures(inst, operands, opCount, out);
|
||||
#endif
|
||||
|
||||
return DebugUtils::errored(kErrorInvalidArch);
|
||||
|
||||
@@ -303,6 +303,9 @@ public:
|
||||
ASMJIT_INLINE_NODEBUG arm::CondCode armCondCode() const noexcept { return (arm::CondCode)getInstIdPart<InstIdParts::kARM_Cond>(); }
|
||||
ASMJIT_INLINE_NODEBUG void setArmCondCode(arm::CondCode cc) noexcept { setInstIdPart<InstIdParts::kARM_Cond>(uint32_t(cc)); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG a32::DataType armDt() const noexcept { return (a32::DataType)getInstIdPart<InstIdParts::kA32_DT>(); }
|
||||
ASMJIT_INLINE_NODEBUG a32::DataType armDt2() const noexcept { return (a32::DataType)getInstIdPart<InstIdParts::kA32_DT2>(); }
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Statics
|
||||
@@ -312,12 +315,12 @@ public:
|
||||
return id | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value);
|
||||
}
|
||||
|
||||
static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, arm::DataType dt, arm::CondCode cc = arm::CondCode::kAL) noexcept {
|
||||
static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, a32::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 ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, arm::DataType dt, arm::DataType dt2, arm::CondCode cc = arm::CondCode::kAL) noexcept {
|
||||
static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, a32::DataType dt, a32::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);
|
||||
@@ -344,16 +347,16 @@ enum class CpuRWFlags : uint32_t {
|
||||
// Common RW Flags (0x000000FF)
|
||||
// ----------------------------
|
||||
|
||||
//! Carry flag.
|
||||
kCF = 0x00000001u,
|
||||
//! Signed overflow flag.
|
||||
kOF = 0x00000002u,
|
||||
//! Sign flag (negative/sign, if set).
|
||||
kSF = 0x00000004u,
|
||||
kOF = 0x00000001u,
|
||||
//! Carry flag.
|
||||
kCF = 0x00000002u,
|
||||
//! Zero and/or equality flag (1 if zero/equal).
|
||||
kZF = 0x00000008u,
|
||||
kZF = 0x00000004u,
|
||||
//! Sign flag (negative/sign, if set).
|
||||
kSF = 0x00000008u,
|
||||
|
||||
// X86 Specific RW Flags (0xFFFFFF00)
|
||||
// X86 Specific RW Flags
|
||||
// ----------------------------------
|
||||
|
||||
//! Carry flag (X86, X86_64).
|
||||
@@ -384,12 +387,22 @@ enum class CpuRWFlags : uint32_t {
|
||||
//! FPU C2 status flag (X86, X86_64).
|
||||
kX86_C2 = 0x00040000u,
|
||||
//! FPU C3 status flag (X86, X86_64).
|
||||
kX86_C3 = 0x00080000u
|
||||
kX86_C3 = 0x00080000u,
|
||||
|
||||
// ARM Specific RW Flags
|
||||
// ----------------------------------
|
||||
|
||||
kARM_V = kOF,
|
||||
kARM_C = kCF,
|
||||
kARM_Z = kZF,
|
||||
kARM_N = kSF,
|
||||
kARM_Q = 0x00000100u,
|
||||
kARM_GE = 0x00000200u
|
||||
};
|
||||
ASMJIT_DEFINE_ENUM_FLAGS(CpuRWFlags)
|
||||
|
||||
//! Operand read/write flags describe how the operand is accessed and some additional features.
|
||||
enum class OpRWFlags {
|
||||
enum class OpRWFlags : uint32_t {
|
||||
//! No flags.
|
||||
kNone = 0,
|
||||
|
||||
|
||||
101
src/asmjit/core/instdb.cpp
Normal file
101
src/asmjit/core/instdb.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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
|
||||
|
||||
#include "../core/api-build_p.h"
|
||||
#include "../core/instdb_p.h"
|
||||
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
namespace InstNameUtils {
|
||||
|
||||
static constexpr uint32_t kBufferSize = 32;
|
||||
|
||||
static ASMJIT_FORCE_INLINE char decode5BitChar(uint32_t c) noexcept {
|
||||
uint32_t base = c <= 26 ? uint32_t('a') - 1u : uint32_t('0') - 27u;
|
||||
return char(base + c);
|
||||
}
|
||||
|
||||
static ASMJIT_FORCE_INLINE size_t decodeToBuffer(char nameOut[kBufferSize], uint32_t nameValue, const char* stringTable) noexcept {
|
||||
size_t i;
|
||||
|
||||
if (nameValue & 0x80000000u) {
|
||||
// Small string of 5-bit characters.
|
||||
for (i = 0; i < 6; i++, nameValue >>= 5) {
|
||||
uint32_t c = nameValue & 0x1F;
|
||||
if (c == 0)
|
||||
break;
|
||||
nameOut[i] = decode5BitChar(c);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
else {
|
||||
size_t prefixBase = nameValue & 0xFFFu;
|
||||
size_t prefixSize = (nameValue >> 12) & 0xFu;
|
||||
|
||||
size_t suffixBase = (nameValue >> 16) & 0xFFFu;
|
||||
size_t suffixSize = (nameValue >> 28) & 0x7u;
|
||||
|
||||
for (i = 0; i < prefixSize; i++)
|
||||
nameOut[i] = stringTable[prefixBase + i];
|
||||
|
||||
char* suffixOut = nameOut + prefixSize;
|
||||
for (i = 0; i < suffixSize; i++)
|
||||
suffixOut[i] = stringTable[suffixBase + i];
|
||||
|
||||
return prefixSize + suffixSize;
|
||||
}
|
||||
}
|
||||
|
||||
Error decode(String& output, uint32_t nameValue, const char* stringTable) noexcept {
|
||||
char nameData[kBufferSize];
|
||||
size_t nameSize = decodeToBuffer(nameData, nameValue, stringTable);
|
||||
|
||||
return output.append(nameData, nameSize);
|
||||
}
|
||||
|
||||
InstId find(const char* s, size_t len, const InstNameIndex& nameIndex, const uint32_t* nameTable, const char* stringTable) noexcept {
|
||||
if (ASMJIT_UNLIKELY(!s))
|
||||
return BaseInst::kIdNone;
|
||||
|
||||
if (len == SIZE_MAX)
|
||||
len = strlen(s);
|
||||
|
||||
if (ASMJIT_UNLIKELY(len == 0 || len > nameIndex.maxNameLength))
|
||||
return BaseInst::kIdNone;
|
||||
|
||||
uint32_t prefix = uint32_t(s[0]) - 'a';
|
||||
if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
|
||||
return BaseInst::kIdNone;
|
||||
|
||||
size_t base = nameIndex.data[prefix].start;
|
||||
size_t end = nameIndex.data[prefix].end;
|
||||
|
||||
if (ASMJIT_UNLIKELY(!base))
|
||||
return BaseInst::kIdNone;
|
||||
|
||||
char nameData[kBufferSize];
|
||||
for (size_t lim = end - base; lim != 0; lim >>= 1) {
|
||||
size_t instId = base + (lim >> 1);
|
||||
size_t nameSize = decodeToBuffer(nameData, nameTable[instId], stringTable);
|
||||
|
||||
int result = Support::compareStringViews(s, len, nameData, nameSize);
|
||||
if (result < 0)
|
||||
continue;
|
||||
|
||||
if (result > 0) {
|
||||
base = instId + 1;
|
||||
lim--;
|
||||
continue;
|
||||
}
|
||||
|
||||
return InstId(instId);
|
||||
}
|
||||
|
||||
return BaseInst::kIdNone;
|
||||
}
|
||||
|
||||
} // {InstNameUtils}
|
||||
|
||||
ASMJIT_END_NAMESPACE
|
||||
40
src/asmjit/core/instdb_p.h
Normal file
40
src/asmjit/core/instdb_p.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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
|
||||
|
||||
#ifndef ASMJIT_CORE_INSTDB_P_H_INCLUDED
|
||||
#define ASMJIT_CORE_INSTDB_P_H_INCLUDED
|
||||
|
||||
#include "../core/inst.h"
|
||||
#include "../core/string.h"
|
||||
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
//! \cond INTERNAL
|
||||
//! \addtogroup asmjit_instruction_db
|
||||
//! \{
|
||||
|
||||
struct InstNameIndex {
|
||||
struct Span {
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
Span data[26];
|
||||
uint16_t maxNameLength;
|
||||
};
|
||||
|
||||
namespace InstNameUtils {
|
||||
|
||||
Error decode(String& output, uint32_t nameValue, const char* stringTable) noexcept;
|
||||
InstId find(const char* s, size_t len, const InstNameIndex& nameIndex, const uint32_t* nameTable, const char* stringTable) noexcept;
|
||||
|
||||
} // {InstNameUtils}
|
||||
|
||||
//! \}
|
||||
//! \endcond
|
||||
|
||||
ASMJIT_END_NAMESPACE
|
||||
|
||||
#endif // ASMJIT_CORE_INSTDB_P_H_INCLUDED
|
||||
@@ -23,13 +23,15 @@ enum class OperandType : uint32_t {
|
||||
kReg = 1,
|
||||
//! Operand is a memory.
|
||||
kMem = 2,
|
||||
//! Operand is a register-list.
|
||||
kRegList = 3,
|
||||
//! Operand is an immediate value.
|
||||
kImm = 3,
|
||||
kImm = 4,
|
||||
//! Operand is a label.
|
||||
kLabel = 4,
|
||||
kLabel = 5,
|
||||
|
||||
//! Maximum value of `OperandType`.
|
||||
kMaxValue = kLabel
|
||||
kMaxValue = kRegList
|
||||
};
|
||||
|
||||
static_assert(uint32_t(OperandType::kMem) == uint32_t(OperandType::kReg) + 1,
|
||||
@@ -47,7 +49,7 @@ enum class RegType : uint8_t {
|
||||
//! No register - unused, invalid, multiple meanings.
|
||||
kNone = 0,
|
||||
|
||||
//! This is not a register type. This value is reserved for a \ref Label that used in \ref BaseMem as a base.
|
||||
//! This is not a register type. This value is reserved for a \ref Label that's used in \ref BaseMem as a base.
|
||||
//!
|
||||
//! Label tag is used as a sub-type, forming a unique signature across all operand types as 0x1 is never associated
|
||||
//! with any register type. This means that a memory operand's BASE register can be constructed from virtually any
|
||||
@@ -55,7 +57,7 @@ enum class RegType : uint8_t {
|
||||
kLabelTag = 1,
|
||||
|
||||
//! Universal type describing program counter (PC) or instruction pointer (IP) register, if the target architecture
|
||||
//! actually exposes it as a separate register type, which most modern targets do.
|
||||
//! actually exposes it as a separate register type, which most modern architectures do.
|
||||
kPC = 2,
|
||||
|
||||
//! 8-bit low general purpose register (X86).
|
||||
@@ -64,21 +66,21 @@ enum class RegType : uint8_t {
|
||||
kGp8Hi = 4,
|
||||
//! 16-bit general purpose register (X86).
|
||||
kGp16 = 5,
|
||||
//! 32-bit general purpose register (X86|ARM).
|
||||
//! 32-bit general purpose register (X86|AArch32|AArch64).
|
||||
kGp32 = 6,
|
||||
//! 64-bit general purpose register (X86|ARM).
|
||||
//! 64-bit general purpose register (X86|AArch64).
|
||||
kGp64 = 7,
|
||||
//! 8-bit view of a vector register (ARM).
|
||||
//! 8-bit view of a vector register (AArch64).
|
||||
kVec8 = 8,
|
||||
//! 16-bit view of a vector register (ARM).
|
||||
//! 16-bit view of a vector register (AArch64).
|
||||
kVec16 = 9,
|
||||
//! 32-bit view of a vector register (ARM).
|
||||
//! 32-bit view of a vector register (AArch32|AArch64).
|
||||
kVec32 = 10,
|
||||
//! 64-bit view of a vector register (ARM).
|
||||
//! 64-bit view of a vector register (AArch32|AArch64).
|
||||
//!
|
||||
//! \note This is never used for MMX registers on X86, MMX registers have its own category.
|
||||
kVec64 = 11,
|
||||
//! 128-bit view of a vector register (X86|ARM).
|
||||
//! 128-bit view of a vector register (X86|AArch32|AArch64).
|
||||
kVec128 = 12,
|
||||
//! 256-bit view of a vector register (X86).
|
||||
kVec256 = 13,
|
||||
@@ -98,9 +100,6 @@ enum class RegType : uint8_t {
|
||||
// X86 Specific Register Types
|
||||
// ---------------------------
|
||||
|
||||
// X86 Specific Register Types
|
||||
// ===========================
|
||||
|
||||
//! Instruction pointer (RIP), only addressable in \ref x86::Mem in 64-bit targets.
|
||||
kX86_Rip = kPC,
|
||||
//! Low GPB register (AL, BL, CL, DL, ...).
|
||||
@@ -137,7 +136,7 @@ enum class RegType : uint8_t {
|
||||
kX86_Tmm = kExtra + 6,
|
||||
|
||||
// ARM Specific Register Types
|
||||
// ===========================
|
||||
// ---------------------------
|
||||
|
||||
//! Program pointer (PC) register (AArch64).
|
||||
kARM_PC = kPC,
|
||||
@@ -615,6 +614,10 @@ struct Operand_ {
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isNone() const noexcept { return _signature == Signature::fromBits(0); }
|
||||
//! Tests whether the operand is a register (`OperandType::kReg`).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg() const noexcept { return opType() == OperandType::kReg; }
|
||||
//! Tests whether the operand is a register-list.
|
||||
//!
|
||||
//! \note Register-list is currently only used by 32-bit ARM architecture.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isRegList() const noexcept { return opType() == OperandType::kRegList; }
|
||||
//! Tests whether the operand is a memory location (`OperandType::kMem`).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isMem() const noexcept { return opType() == OperandType::kMem; }
|
||||
//! Tests whether the operand is an immediate (`OperandType::kImm`).
|
||||
@@ -654,16 +657,34 @@ struct Operand_ {
|
||||
return _signature.subset(Signature::kOpTypeMask | Signature::kRegTypeMask) == (Signature::fromOpType(OperandType::kReg) | Signature::fromRegType(type));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register matching the given register `type`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isRegList(RegType type) const noexcept {
|
||||
return _signature.subset(Signature::kOpTypeMask | Signature::kRegTypeMask) == (Signature::fromOpType(OperandType::kRegList) | Signature::fromRegType(type));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is register and of register `type` and `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegType type, uint32_t id) const noexcept {
|
||||
return isReg(type) && this->id() == id;
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isReg(RegType type, uint32_t regId) const noexcept {
|
||||
return isReg(type) && _baseId == regId;
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register or memory.
|
||||
//!
|
||||
//! \note This is useful on X86 and X86_64 architectures as many instructions support Reg/Mem operand combination.
|
||||
//! So if the user code works with just \ref Operand, it's possible to check whether the operand is either a register
|
||||
//! or memory location with a single check.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isRegOrMem() const noexcept {
|
||||
return Support::isBetween<uint32_t>(uint32_t(opType()), uint32_t(OperandType::kReg), uint32_t(OperandType::kMem));
|
||||
}
|
||||
|
||||
//! Tests whether the operand is a register, register-list, or memory.
|
||||
//!
|
||||
//! \note This is useful on 32-bit ARM architecture to check whether an operand references a register. It can be
|
||||
//! used in other architectures too, but it would work identically to \ref isRegOrMem() as other architectures
|
||||
//! don't provide register lists.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isRegOrRegListOrMem() const noexcept {
|
||||
return Support::isBetween<uint32_t>(uint32_t(opType()), uint32_t(OperandType::kReg), uint32_t(OperandType::kRegList));
|
||||
}
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Accessors (X86 Specific)
|
||||
@@ -818,10 +839,8 @@ struct BaseRegTraits {
|
||||
kTypeId = uint32_t(TypeId::kVoid),
|
||||
//! RegType is not valid by default.
|
||||
kValid = 0,
|
||||
//! Count of registers (0 if none).
|
||||
kCount = 0,
|
||||
|
||||
//! Zero type by default (defeaults to None).
|
||||
//! Zero type by default (defaults to None).
|
||||
kType = uint32_t(RegType::kNone),
|
||||
//! Zero group by default (defaults to GP).
|
||||
kGroup = uint32_t(RegGroup::kGp),
|
||||
@@ -834,7 +853,7 @@ struct BaseRegTraits {
|
||||
};
|
||||
//! \endcond
|
||||
|
||||
//! Physical or virtual register operand.
|
||||
//! Physical or virtual register operand (base).
|
||||
class BaseReg : public Operand {
|
||||
public:
|
||||
//! \name Constants
|
||||
@@ -916,7 +935,7 @@ public:
|
||||
}
|
||||
|
||||
//! Tests whether the register is valid (either virtual or physical).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isValid() const noexcept { return (_signature != 0) & (_baseId != kIdBad); }
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isValid() const noexcept { return bool(unsigned(_signature != 0) & unsigned(_baseId != kIdBad)); }
|
||||
|
||||
//! Tests whether this is a physical register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isPhysReg() const noexcept { return _baseId < kIdBad; }
|
||||
@@ -1098,13 +1117,10 @@ struct RegOnly {
|
||||
|
||||
//! \cond INTERNAL
|
||||
//! Adds a template specialization for `REG_TYPE` into the local `RegTraits`.
|
||||
#define ASMJIT_DEFINE_REG_TRAITS(REG, REG_TYPE, GROUP, SIZE, COUNT, TYPE_ID) \
|
||||
#define ASMJIT_DEFINE_REG_TRAITS(REG_TYPE, GROUP, SIZE, TYPE_ID) \
|
||||
template<> \
|
||||
struct RegTraits<REG_TYPE> { \
|
||||
typedef REG RegT; \
|
||||
\
|
||||
static constexpr uint32_t kValid = 1; \
|
||||
static constexpr uint32_t kCount = COUNT; \
|
||||
static constexpr RegType kType = REG_TYPE; \
|
||||
static constexpr RegGroup kGroup = GROUP; \
|
||||
static constexpr uint32_t kSize = SIZE; \
|
||||
@@ -1168,6 +1184,196 @@ public:
|
||||
: BASE(Signature{kSignature}, id) {}
|
||||
//! \endcond
|
||||
|
||||
//! List of physical registers (base).
|
||||
//!
|
||||
//! \note List of registers is only used by some ARM instructions at the moment.
|
||||
class BaseRegList : public Operand {
|
||||
public:
|
||||
//! \name Constants
|
||||
//! \{
|
||||
|
||||
enum : uint32_t {
|
||||
kSignature = Signature::fromOpType(OperandType::kRegList).bits()
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
|
||||
//! Creates a dummy register operand.
|
||||
ASMJIT_INLINE_NODEBUG constexpr BaseRegList() noexcept
|
||||
: Operand(Globals::Init, Signature::fromOpType(OperandType::kRegList), 0, 0, 0) {}
|
||||
|
||||
//! Creates a new register operand which is the same as `other` .
|
||||
ASMJIT_INLINE_NODEBUG constexpr BaseRegList(const BaseRegList& other) noexcept
|
||||
: Operand(other) {}
|
||||
|
||||
//! Creates a new register operand compatible with `other`, but with a different `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr BaseRegList(const BaseRegList& other, RegMask regMask) noexcept
|
||||
: Operand(Globals::Init, other._signature, regMask, 0, 0) {}
|
||||
|
||||
//! Creates a register initialized to the given `signature` and `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr BaseRegList(const Signature& signature, RegMask regMask) noexcept
|
||||
: Operand(Globals::Init, signature, regMask, 0, 0) {}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG explicit BaseRegList(Globals::NoInit_) noexcept
|
||||
: Operand(Globals::NoInit) {}
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Overloaded Operators
|
||||
//! \{
|
||||
|
||||
ASMJIT_INLINE_NODEBUG BaseRegList& operator=(const BaseRegList& other) noexcept = default;
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Accessors
|
||||
//! \{
|
||||
|
||||
//! Tests whether the register-list is valid, which means it has a type and at least a single register in the list.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isValid() const noexcept { return bool(unsigned(_signature != 0u) & unsigned(_baseId != 0u)); }
|
||||
|
||||
//! Tests whether the register type matches `type` - same as `isReg(type)`, provided for convenience.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isType(RegType type) const noexcept { return _signature.subset(Signature::kRegTypeMask) == Signature::fromRegType(type); }
|
||||
//! Tests whether the register group matches `group`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGroup(RegGroup group) const noexcept { return _signature.subset(Signature::kRegGroupMask) == Signature::fromRegGroup(group); }
|
||||
|
||||
//! Tests whether the register is a general purpose register (any size).
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isGp() const noexcept { return isGroup(RegGroup::kGp); }
|
||||
//! Tests whether the register is a vector register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr bool isVec() const noexcept { return isGroup(RegGroup::kVec); }
|
||||
|
||||
//! Returns the register type.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegType type() const noexcept { return _signature.regType(); }
|
||||
//! Returns the register group.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegGroup group() const noexcept { return _signature.regGroup(); }
|
||||
//! Returns the size of a single register in this register-list or 0 if unspecified.
|
||||
ASMJIT_INLINE_NODEBUG constexpr uint32_t size() const noexcept { return _signature.getField<Signature::kSizeMask>(); }
|
||||
|
||||
//! Returns the register list as a mask, where each bit represents one physical register.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegMask list() const noexcept { return _baseId; }
|
||||
//! Sets the register list to `mask`.
|
||||
ASMJIT_INLINE_NODEBUG void setList(RegMask mask) noexcept { _baseId = mask; }
|
||||
//! Remoes all registers from the register-list by making the underlying register-mask zero.
|
||||
ASMJIT_INLINE_NODEBUG void resetList() noexcept { _baseId = 0; }
|
||||
|
||||
//! Adds registers passed by a register `mask` to the register-list.
|
||||
ASMJIT_INLINE_NODEBUG void addList(RegMask mask) noexcept { _baseId |= mask; }
|
||||
//! Removes registers passed by a register `mask` to the register-list.
|
||||
ASMJIT_INLINE_NODEBUG void clearList(RegMask mask) noexcept { _baseId &= ~mask; }
|
||||
//! Uses AND operator to combine the current register-list with other register `mask`.
|
||||
ASMJIT_INLINE_NODEBUG void andList(RegMask mask) noexcept { _baseId &= mask; }
|
||||
//! Uses XOR operator to combine the current register-list with other register `mask`.
|
||||
ASMJIT_INLINE_NODEBUG void xorList(RegMask mask) noexcept { _baseId ^= mask; }
|
||||
|
||||
//! Checks whether a physical register `physId` is in the register-list.
|
||||
ASMJIT_INLINE_NODEBUG bool hasReg(uint32_t physId) const noexcept { return physId < 32u ? (_baseId & (1u << physId)) != 0 : false; }
|
||||
//! Adds a physical register `physId` to the register-list.
|
||||
ASMJIT_INLINE_NODEBUG void addReg(uint32_t physId) noexcept { addList(1u << physId); }
|
||||
//! Removes a physical register `physId` from the register-list.
|
||||
ASMJIT_INLINE_NODEBUG void clearReg(uint32_t physId) noexcept { clearList(1u << physId); }
|
||||
|
||||
//! Clones the register-list operand.
|
||||
ASMJIT_INLINE_NODEBUG constexpr BaseRegList clone() const noexcept { return BaseRegList(*this); }
|
||||
|
||||
//! Casts this register to `RegT` by also changing its signature.
|
||||
//!
|
||||
//! \note Improper use of `cloneAs()` can lead to hard-to-debug errors.
|
||||
template<typename RegListT>
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT cloneAs() const noexcept { return RegListT(Signature(RegListT::kSignature), list()); }
|
||||
|
||||
//! Casts this register to `other` by also changing its signature.
|
||||
//!
|
||||
//! \note Improper use of `cloneAs()` can lead to hard-to-debug errors.
|
||||
template<typename RegListT>
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT cloneAs(const RegListT& other) const noexcept { return RegListT(other.signature(), list()); }
|
||||
|
||||
//! \}
|
||||
};
|
||||
|
||||
template<typename RegT>
|
||||
class RegListT : public BaseRegList {
|
||||
public:
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
|
||||
//! Creates a dummy register operand.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT() noexcept
|
||||
: BaseRegList() {}
|
||||
|
||||
//! Creates a new register operand which is the same as `other` .
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT(const RegListT& other) noexcept
|
||||
: BaseRegList(other) {}
|
||||
|
||||
//! Creates a new register operand compatible with `other`, but with a different `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT(const RegListT& other, RegMask regMask) noexcept
|
||||
: BaseRegList(other, regMask) {}
|
||||
|
||||
//! Creates a register initialized to the given `signature` and `id`.
|
||||
ASMJIT_INLINE_NODEBUG constexpr RegListT(const Signature& signature, RegMask regMask) noexcept
|
||||
: BaseRegList(signature, regMask) {}
|
||||
|
||||
//! Creates a register initialized to the given `signature` and `regs`.
|
||||
ASMJIT_INLINE_NODEBUG RegListT(const Signature& signature, std::initializer_list<RegT> regs) noexcept
|
||||
: BaseRegList(signature, RegMask(0)) { addRegs(regs); }
|
||||
|
||||
ASMJIT_INLINE_NODEBUG explicit RegListT(Globals::NoInit_) noexcept
|
||||
: BaseRegList(Globals::NoInit) {}
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Overloaded Operators
|
||||
//! \{
|
||||
|
||||
ASMJIT_INLINE_NODEBUG RegListT& operator=(const RegListT& other) noexcept = default;
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Accessors
|
||||
//! \{
|
||||
|
||||
using BaseRegList::addList;
|
||||
using BaseRegList::clearList;
|
||||
using BaseRegList::andList;
|
||||
using BaseRegList::xorList;
|
||||
|
||||
//! Adds registers to this register-list as provided by `other` register-list.
|
||||
ASMJIT_INLINE_NODEBUG void addList(const RegListT<RegT>& other) noexcept { addList(other.list()); }
|
||||
//! Removes registers contained in `other` register-list.
|
||||
ASMJIT_INLINE_NODEBUG void clearList(const RegListT<RegT>& other) noexcept { clearList(other.list()); }
|
||||
//! Uses AND operator to combine the current register-list with `other` register-list.
|
||||
ASMJIT_INLINE_NODEBUG void andList(const RegListT<RegT>& other) noexcept { andList(other.list()); }
|
||||
//! Uses XOR operator to combine the current register-list with `other` register-list.
|
||||
ASMJIT_INLINE_NODEBUG void xorList(const RegListT<RegT>& other) noexcept { xorList(other.list()); }
|
||||
|
||||
using BaseRegList::addReg;
|
||||
using BaseRegList::clearReg;
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void addReg(const RegT& reg) noexcept {
|
||||
if (reg.id() < 32u)
|
||||
addReg(reg.id());
|
||||
}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void addRegs(std::initializer_list<RegT> regs) noexcept {
|
||||
for (const RegT& reg : regs)
|
||||
addReg(reg);
|
||||
}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void clearReg(const RegT& reg) noexcept {
|
||||
if (reg.id() < 32u)
|
||||
clearReg(reg.id());
|
||||
}
|
||||
|
||||
ASMJIT_INLINE_NODEBUG void clearRegs(std::initializer_list<RegT> regs) noexcept {
|
||||
for (const RegT& reg : regs)
|
||||
clearReg(reg);
|
||||
}
|
||||
|
||||
//! \}
|
||||
};
|
||||
|
||||
//! Base class for all memory operands.
|
||||
//!
|
||||
//! The data is split into the following parts:
|
||||
|
||||
@@ -925,19 +925,6 @@ static ASMJIT_INLINE_NODEBUG const char* findPackedString(const char* p, uint32_
|
||||
return p;
|
||||
}
|
||||
|
||||
//! Compares two instruction names.
|
||||
//!
|
||||
//! `a` is a null terminated instruction name from arch-specific `nameData[]`
|
||||
//! table. `b` is a possibly non-null terminated instruction name passed to
|
||||
//! `InstAPI::stringToInstId()`.
|
||||
static ASMJIT_FORCE_INLINE int cmpInstName(const char* a, const char* b, size_t size) noexcept {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
int c = int(uint8_t(a[i])) - int(uint8_t(b[i]));
|
||||
if (c != 0) return c;
|
||||
}
|
||||
return int(uint8_t(a[size]));
|
||||
}
|
||||
|
||||
//! Compares two string views.
|
||||
static ASMJIT_FORCE_INLINE int compareStringViews(const char* aData, size_t aSize, const char* bData, size_t bSize) noexcept {
|
||||
size_t size = Support::min(aSize, bSize);
|
||||
@@ -950,6 +937,7 @@ static ASMJIT_FORCE_INLINE int compareStringViews(const char* aData, size_t aSiz
|
||||
|
||||
return int(aSize) - int(bSize);
|
||||
}
|
||||
|
||||
// Support - Memory Read Access - 8 Bits
|
||||
// =====================================
|
||||
|
||||
|
||||
@@ -16,43 +16,6 @@ ASMJIT_BEGIN_NAMESPACE
|
||||
namespace Support {
|
||||
|
||||
//! \cond INTERNAL
|
||||
|
||||
static ASMJIT_FORCE_INLINE char decode5BitChar(uint32_t c) noexcept {
|
||||
uint32_t base = c <= 26 ? uint32_t('a') - 1u : uint32_t('0') - 27u;
|
||||
return char(base + c);
|
||||
}
|
||||
|
||||
static ASMJIT_FORCE_INLINE size_t decodeInstName(char nameOut[32], uint32_t index, const char* stringTable) noexcept {
|
||||
size_t i;
|
||||
|
||||
if (index & 0x80000000u) {
|
||||
// Small string of 5-bit characters.
|
||||
for (i = 0; i < 6; i++, index >>= 5) {
|
||||
uint32_t c = index & 0x1F;
|
||||
if (c == 0)
|
||||
break;
|
||||
nameOut[i] = decode5BitChar(c);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
else {
|
||||
size_t prefixBase = index & 0xFFFu;
|
||||
size_t prefixSize = (index >> 12) & 0xFu;
|
||||
|
||||
size_t suffixBase = (index >> 16) & 0xFFFu;
|
||||
size_t suffixSize = (index >> 28) & 0x7u;
|
||||
|
||||
for (i = 0; i < prefixSize; i++)
|
||||
nameOut[i] = stringTable[prefixBase + i];
|
||||
|
||||
char* suffixOut = nameOut + prefixSize;
|
||||
for (i = 0; i < suffixSize; i++)
|
||||
suffixOut[i] = stringTable[suffixBase + i];
|
||||
|
||||
return prefixSize + suffixSize;
|
||||
}
|
||||
}
|
||||
|
||||
//! \endcond
|
||||
|
||||
} // {Support}
|
||||
|
||||
@@ -996,8 +996,8 @@ void protectJitMemory(ProtectJitAccess access) noexcept {
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
// JitAllocator - Tests
|
||||
// ====================
|
||||
// Virtual Memory - Tests
|
||||
// ======================
|
||||
|
||||
#if defined(ASMJIT_TEST)
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
@@ -275,7 +275,7 @@ public:
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Construction / Destruction
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
|
||||
//! Makes the given memory block RW protected.
|
||||
|
||||
@@ -529,8 +529,6 @@ static ASMJIT_FORCE_INLINE bool x86ShouldUseMovabs(Assembler* self, X86BufferWri
|
||||
Assembler::Assembler(CodeHolder* code) noexcept : BaseAssembler() {
|
||||
_archMask = (uint64_t(1) << uint32_t(Arch::kX86)) |
|
||||
(uint64_t(1) << uint32_t(Arch::kX64)) ;
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -610,7 +608,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, con
|
||||
Operand_ opArray[Globals::kMaxOpCount];
|
||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||
|
||||
err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
|
||||
err = _funcs.validate(BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
|
||||
if (ASMJIT_UNLIKELY(err))
|
||||
goto Failed;
|
||||
}
|
||||
@@ -5088,6 +5086,9 @@ Error Assembler::onAttach(CodeHolder* code) noexcept {
|
||||
Arch arch = code->arch();
|
||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||
|
||||
_instructionAlignment = uint8_t(1);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (Environment::is32Bit(arch)) {
|
||||
// 32 bit architecture - X86.
|
||||
_forcedInstOptions |= InstOptions::kX86_InvalidRex;
|
||||
|
||||
@@ -18,8 +18,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
||||
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
|
||||
_archMask = (uint64_t(1) << uint32_t(Arch::kX86)) |
|
||||
(uint64_t(1) << uint32_t(Arch::kX64)) ;
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -29,7 +27,12 @@ Builder::~Builder() noexcept {}
|
||||
// =====================
|
||||
|
||||
Error Builder::onAttach(CodeHolder* code) noexcept {
|
||||
return Base::onAttach(code);
|
||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||
|
||||
_instructionAlignment = uint8_t(1);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error Builder::onDetach(CodeHolder* code) noexcept {
|
||||
|
||||
@@ -19,8 +19,6 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
||||
Compiler::Compiler(CodeHolder* code) noexcept : BaseCompiler() {
|
||||
_archMask = (uint64_t(1) << uint32_t(Arch::kX86)) |
|
||||
(uint64_t(1) << uint32_t(Arch::kX64)) ;
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
if (code)
|
||||
code->attach(this);
|
||||
}
|
||||
@@ -38,6 +36,9 @@ Error Compiler::onAttach(CodeHolder* code) noexcept {
|
||||
return err;
|
||||
}
|
||||
|
||||
_instructionAlignment = uint8_t(1);
|
||||
assignEmitterFuncs(this);
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
|
||||
@@ -616,7 +616,7 @@ void assignEmitterFuncs(BaseEmitter* emitter) {
|
||||
#endif
|
||||
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
emitter->_funcs.validate = InstInternal::validate;
|
||||
emitter->_funcs.validate = emitter->is32Bit() ? InstInternal::validateX86 : InstInternal::validateX64;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -139,8 +139,8 @@ struct EmitterExplicitT {
|
||||
|
||||
// These two are unfortunately reported by the sanitizer. We know what we do, however, the sanitizer doesn't.
|
||||
// I have tried to use reinterpret_cast instead, but that would generate bad code when compiled by MSC.
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF inline This* _emitter() noexcept { return static_cast<This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF inline const This* _emitter() const noexcept { return static_cast<const This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF ASMJIT_INLINE_NODEBUG This* _emitter() noexcept { return static_cast<This*>(this); }
|
||||
ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF ASMJIT_INLINE_NODEBUG const This* _emitter() const noexcept { return static_cast<const This*>(this); }
|
||||
|
||||
//! \endcond
|
||||
|
||||
|
||||
@@ -95,6 +95,24 @@ struct RegFormatInfo_T {
|
||||
X == uint32_t(RegType::kX86_Gpd ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_Gpq ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_SReg ) ? 7 :
|
||||
X == uint32_t(RegType::kX86_Rip ) ? 1 : 0,
|
||||
|
||||
kRegCount = X == uint32_t(RegType::kX86_GpbLo) ? 32 :
|
||||
X == uint32_t(RegType::kX86_GpbHi) ? 4 :
|
||||
X == uint32_t(RegType::kX86_Gpw ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Gpd ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Gpq ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Xmm ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Ymm ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Zmm ) ? 32 :
|
||||
X == uint32_t(RegType::kX86_Mm ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_KReg ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_SReg ) ? 7 :
|
||||
X == uint32_t(RegType::kX86_CReg ) ? 16 :
|
||||
X == uint32_t(RegType::kX86_DReg ) ? 16 :
|
||||
X == uint32_t(RegType::kX86_St ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_Bnd ) ? 4 :
|
||||
X == uint32_t(RegType::kX86_Tmm ) ? 8 :
|
||||
X == uint32_t(RegType::kX86_Rip ) ? 1 : 0
|
||||
};
|
||||
};
|
||||
@@ -104,7 +122,7 @@ struct RegFormatInfo_T {
|
||||
}
|
||||
|
||||
#define ASMJIT_REG_NAME_ENTRY(TYPE) { \
|
||||
RegTraits<RegType(TYPE)>::kCount, \
|
||||
RegFormatInfo_T<TYPE>::kRegCount, \
|
||||
RegFormatInfo_T<TYPE>::kFormatIndex, \
|
||||
RegFormatInfo_T<TYPE>::kSpecialIndex, \
|
||||
RegFormatInfo_T<TYPE>::kSpecialCount \
|
||||
@@ -911,7 +929,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
ASMJIT_PROPAGATE(InstInternal::instIdToString(arch, instId, sb));
|
||||
ASMJIT_PROPAGATE(InstInternal::instIdToString(instId, sb));
|
||||
}
|
||||
else {
|
||||
ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
|
||||
|
||||
@@ -3,30 +3,12 @@
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IMPORTANT: AsmJit now uses an external instruction database to populate
|
||||
// static tables within this file. Perform the following steps to regenerate
|
||||
// all tables enclosed by ${...}:
|
||||
//
|
||||
// 1. Install node.js environment <https://nodejs.org>
|
||||
// 2. Go to asmjit/tools directory
|
||||
// 3. Get the latest asmdb from <https://github.com/asmjit/asmdb> and
|
||||
// copy/link the `asmdb` directory to `asmjit/tools/asmdb`.
|
||||
// 4. Execute `node tablegen-x86.js`
|
||||
//
|
||||
// Instruction encoding and opcodes were added to the `x86inst.cpp` database
|
||||
// manually in the past and they are not updated by the script as it became
|
||||
// tricky. However, everything else is updated including instruction operands
|
||||
// and tables required to validate them, instruction read/write information
|
||||
// (including registers and flags), and all indexes to all tables.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "../core/api-build_p.h"
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
|
||||
#include "../core/cpuinfo.h"
|
||||
#include "../core/instdb_p.h"
|
||||
#include "../core/misc_p.h"
|
||||
#include "../core/support_p.h"
|
||||
#include "../x86/x86instapi_p.h"
|
||||
#include "../x86/x86instdb_p.h"
|
||||
#include "../x86/x86opcode_p.h"
|
||||
@@ -34,63 +16,21 @@
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
||||
|
||||
namespace InstInternal {
|
||||
|
||||
// x86::InstInternal - Text
|
||||
// ========================
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noexcept {
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
Error instIdToString(InstId instId, String& output) noexcept {
|
||||
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId)))
|
||||
return DebugUtils::errored(kErrorInvalidInstruction);
|
||||
|
||||
char nameData[32];
|
||||
size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable);
|
||||
|
||||
return output.append(nameData, nameSize);
|
||||
return InstNameUtils::decode(output, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable);
|
||||
}
|
||||
|
||||
InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!s))
|
||||
return Inst::kIdNone;
|
||||
|
||||
if (len == SIZE_MAX)
|
||||
len = strlen(s);
|
||||
|
||||
if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize))
|
||||
return Inst::kIdNone;
|
||||
|
||||
uint32_t prefix = uint32_t(s[0]) - 'a';
|
||||
if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
|
||||
return Inst::kIdNone;
|
||||
|
||||
size_t base = InstDB::instNameIndex[prefix].start;
|
||||
size_t end = InstDB::instNameIndex[prefix].end;
|
||||
|
||||
if (ASMJIT_UNLIKELY(!base))
|
||||
return Inst::kIdNone;
|
||||
|
||||
char nameData[32];
|
||||
for (size_t lim = end - base; lim != 0; lim >>= 1) {
|
||||
size_t instId = base + (lim >> 1);
|
||||
size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable);
|
||||
|
||||
int result = Support::compareStringViews(s, len, nameData, nameSize);
|
||||
if (result < 0)
|
||||
continue;
|
||||
|
||||
if (result > 0) {
|
||||
base = instId + 1;
|
||||
lim--;
|
||||
continue;
|
||||
}
|
||||
|
||||
return InstId(instId);
|
||||
}
|
||||
|
||||
return Inst::kIdNone;
|
||||
InstId stringToInstId(const char* s, size_t len) noexcept {
|
||||
return InstNameUtils::find(s, len, InstDB::instNameIndex, InstDB::_instNameIndexTable, InstDB::_instNameStringTable);
|
||||
}
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
@@ -216,20 +156,11 @@ static ASMJIT_FORCE_INLINE bool x86CheckOSig(const InstDB::OpSignature& op, cons
|
||||
return true;
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE Error InstInternal::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
// Only called when `arch` matches X86 family.
|
||||
ASMJIT_ASSERT(Environment::isFamilyX86(arch));
|
||||
|
||||
const X86ValidationData* vd;
|
||||
if (arch == Arch::kX86)
|
||||
vd = &_x86ValidationData;
|
||||
else
|
||||
vd = &_x64ValidationData;
|
||||
|
||||
static ASMJIT_FAVOR_SIZE Error validate(InstDB::Mode mode, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
uint32_t i;
|
||||
InstDB::Mode mode = InstDB::modeFromArch(arch);
|
||||
|
||||
// Get the instruction data.
|
||||
const X86ValidationData* vd = (mode == InstDB::Mode::kX86) ? &_x86ValidationData : &_x64ValidationData;
|
||||
InstId instId = inst.id();
|
||||
InstOptions options = inst.options();
|
||||
|
||||
@@ -717,6 +648,15 @@ Next:
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
Error validateX86(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
return validate(InstDB::Mode::kX86, inst, operands, opCount, validationFlags);
|
||||
}
|
||||
|
||||
Error validateX64(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
return validate(InstDB::Mode::kX64, inst, operands, opCount, validationFlags);
|
||||
}
|
||||
|
||||
#endif // !ASMJIT_NO_VALIDATION
|
||||
|
||||
// x86::InstInternal - QueryRWInfo
|
||||
@@ -785,7 +725,7 @@ static ASMJIT_FORCE_INLINE bool hasSameRegType(const BaseReg* regs, size_t opCou
|
||||
return true;
|
||||
}
|
||||
|
||||
Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||
Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||
// Only called when `arch` matches X86 family.
|
||||
ASMJIT_ASSERT(Environment::isFamilyX86(arch));
|
||||
|
||||
@@ -1500,7 +1440,7 @@ static inline uint32_t InstInternal_usesAvx512(InstOptions instOptions, const Re
|
||||
return hasEvex | hasKMask | hasKOrZmm;
|
||||
}
|
||||
|
||||
Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
|
||||
Error 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.
|
||||
@@ -1707,6 +1647,8 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
|
||||
}
|
||||
#endif // !ASMJIT_NO_INTROSPECTION
|
||||
|
||||
} // {InstInternal}
|
||||
|
||||
// x86::InstInternal - Tests
|
||||
// =========================
|
||||
|
||||
@@ -1717,12 +1659,12 @@ UNIT(x86_inst_api_text) {
|
||||
INFO("Matching all X86 instructions");
|
||||
for (uint32_t a = 1; a < Inst::_kIdCount; a++) {
|
||||
StringTmp<128> aName;
|
||||
EXPECT_EQ(InstInternal::instIdToString(Arch::kX86, a, aName), kErrorOk)
|
||||
EXPECT_EQ(InstInternal::instIdToString(a, aName), kErrorOk)
|
||||
.message("Failed to get the name of instruction #%u", a);
|
||||
|
||||
uint32_t b = InstInternal::stringToInstId(Arch::kX86, aName.data(), aName.size());
|
||||
uint32_t b = InstInternal::stringToInstId(aName.data(), aName.size());
|
||||
StringTmp<128> bName;
|
||||
InstInternal::instIdToString(Arch::kX86, b, bName);
|
||||
InstInternal::instIdToString(b, bName);
|
||||
EXPECT_EQ(a, b)
|
||||
.message("Instructions do not match \"%s\" (#%u) != \"%s\" (#%u)", aName.data(), a, bName.data(), b);
|
||||
}
|
||||
|
||||
@@ -18,12 +18,13 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
||||
namespace InstInternal {
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
Error ASMJIT_CDECL instIdToString(Arch arch, InstId instId, String& output) noexcept;
|
||||
InstId ASMJIT_CDECL stringToInstId(Arch arch, const char* s, size_t len) noexcept;
|
||||
Error ASMJIT_CDECL instIdToString(InstId instId, String& output) noexcept;
|
||||
InstId ASMJIT_CDECL stringToInstId(const char* s, size_t len) noexcept;
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
Error ASMJIT_CDECL validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
|
||||
Error ASMJIT_CDECL validateX86(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
|
||||
Error ASMJIT_CDECL validateX64(const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept;
|
||||
#endif // !ASMJIT_NO_VALIDATION
|
||||
|
||||
#ifndef ASMJIT_NO_INTROSPECTION
|
||||
|
||||
@@ -3,24 +3,6 @@
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IMPORTANT: AsmJit now uses an external instruction database to populate
|
||||
// static tables within this file. Perform the following steps to regenerate
|
||||
// all tables enclosed by ${...}:
|
||||
//
|
||||
// 1. Install node.js environment <https://nodejs.org>
|
||||
// 2. Go to asmjit/tools directory
|
||||
// 3. Get the latest asmdb from <https://github.com/asmjit/asmdb> and
|
||||
// copy/link the `asmdb` directory to `asmjit/tools/asmdb`.
|
||||
// 4. Execute `node tablegen-x86.js`
|
||||
//
|
||||
// Instruction encoding and opcodes were added to the `x86inst.cpp` database
|
||||
// manually in the past and they are not updated by the script as it became
|
||||
// tricky. However, everything else is updated including instruction operands
|
||||
// and tables required to validate them, instruction read/write information
|
||||
// (including registers and flags), and all indexes to all tables.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "../core/api-build_p.h"
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
|
||||
@@ -2940,6 +2922,65 @@ const InstRWFlags InstDB::_instFlagsTable[] = {
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
// ${NameData:Begin}
|
||||
// ------------------- Automatically generated, do not edit -------------------
|
||||
const InstNameIndex InstDB::instNameIndex = {{
|
||||
{ Inst::kIdAaa , Inst::kIdAxor + 1 },
|
||||
{ Inst::kIdBextr , Inst::kIdBzhi + 1 },
|
||||
{ Inst::kIdCall , Inst::kIdCwde + 1 },
|
||||
{ Inst::kIdDaa , Inst::kIdDpps + 1 },
|
||||
{ Inst::kIdEmms , Inst::kIdExtrq + 1 },
|
||||
{ Inst::kIdF2xm1 , Inst::kIdFyl2xp1 + 1 },
|
||||
{ Inst::kIdGetsec , Inst::kIdGf2p8mulb + 1 },
|
||||
{ Inst::kIdHaddpd , Inst::kIdHsubps + 1 },
|
||||
{ Inst::kIdIdiv , Inst::kIdIretq + 1 },
|
||||
{ Inst::kIdJa , Inst::kIdJz + 1 },
|
||||
{ Inst::kIdKaddb , Inst::kIdKxorw + 1 },
|
||||
{ Inst::kIdLahf , Inst::kIdLzcnt + 1 },
|
||||
{ Inst::kIdMaskmovdqu , Inst::kIdMwaitx + 1 },
|
||||
{ Inst::kIdNeg , Inst::kIdNot + 1 },
|
||||
{ Inst::kIdOr , Inst::kIdOuts + 1 },
|
||||
{ Inst::kIdPabsb , Inst::kIdPxor + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdRcl , Inst::kIdRstorssp + 1 },
|
||||
{ Inst::kIdSahf , Inst::kIdSysretq + 1 },
|
||||
{ Inst::kIdT1mskc , Inst::kIdTzmsk + 1 },
|
||||
{ Inst::kIdUcomisd , Inst::kIdUnpcklps + 1 },
|
||||
{ Inst::kIdV4fmaddps , Inst::kIdVzeroupper + 1 },
|
||||
{ Inst::kIdWbinvd , Inst::kIdWrussq + 1 },
|
||||
{ Inst::kIdXabort , Inst::kIdXtest + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 }
|
||||
}, uint16_t(17)};
|
||||
|
||||
const char InstDB::_instNameStringTable[] =
|
||||
"vgf2p8affineinvqbvaeskeygenassistvbroadcastf32x464x264x4i32x2i32x4i32x8i64x2i64x"
|
||||
"4vpbroadcastmb2w2dvbcstnebf162p128i128vcvtne2ps2vcvtneebf16vcvtneobf16vfmaddsub1"
|
||||
"32ph213pd213ph213ps231pd231ph231psvfmsubadd132vpmultishiftvscatterpf0dqpdqps1dpd"
|
||||
"1dps1qpd1qpsvcvtneps2vextracvextractfvgatherpf0vp2intersecttcmmimfp16tcmmrlfp16s"
|
||||
"h2pssdph2psvfnmadd132213sd213sh213ss231sd231sh231ssvfnmsub132vinservinsertfvpshu"
|
||||
"fbitqvsha512rndprefetchitntawt1saveprevsssha256rndtileloaddtilereleavaesdeclvaes"
|
||||
"enclvcompressvcvttpd2uqqvcvttph2uvcvttps2uvcvttsd2uvcvttsh2uvcvttss2uvfixupimmvf"
|
||||
"madd132vfmsub132vmaskmovdqvpcompressvpconflictvphminposuvpmadd52hluqvpscatterqdv"
|
||||
"punpckhqlqdqvrndscalemsg1msg2clflushopcmpnbexcmpnlexcmpxchg16t0t2tilestorev4fnma"
|
||||
"ddssvcvtpd2uvcvtph2psudqvcvtps2phvcvtsd2uvcvtsh2uvcvtss2uvcvtudq2vcvtuqq2vcvtusi"
|
||||
"2vfcmaddcvfpclassvgetmanmulbvp4dpwssvpclmuvpcmpestrvpcmpistrvperm2fvpermil2vpgat"
|
||||
"hervpmacssdqvpmadcsswubswvpmaskmovpternlogbwwdlbwldqlwdvrsqrt1428pd28ps28sd28ssv"
|
||||
"shufvshuffvzeroupxsaveoptcmpbexcmplexcmpnbxcmpnlxcmpnoxcmpnpxcmpnsxcmpnzx8bfxrst"
|
||||
"orldtilecfmovdir64pvalidarmpadjurmpupdaserialisha1nexsha1rndssttilecftdpbf16tdpf"
|
||||
"p16v4fmadvaddsubvblendmvpdvcvtdq2uwvcvtqq2vcvtsi2vcvtuwvdbpsadvdpbf16vexpanvfcmu"
|
||||
"lccphcshvgetexpvmovdqau16u32u64vmovmskvmovntvmovshdvmovsldvpackssdwbvpackuswbvpb"
|
||||
"lendmdvpdpbssudsvpdpbusvpdpwssvpdpwus2pdvpermtvpexpanvphaddubwqdqhvpmovmskvpmovs"
|
||||
"xbvpmovusqwvpmovzxbvpmulhrvptestnmqvreducevscalefvsm3rndvsm4rndsvunpckhlpdlpsxre"
|
||||
"sldtrs64xsusldtrcldemoclrssbscmpbxcmplxcmpoxcmppxcmpsxcmpzxcvtpifcmovfxsavekorte"
|
||||
"stkshiftrbkunpckmonitorpfrcpipfrsqirtvrdfsbrdgsbsspseamcalsenduisetssbssysesysex"
|
||||
"vcvtwvfmulvldmxcsvmlaundupu8vmovhvmovlhvmpsadvmresumvpadduvpaligngtbgtdgtqgtw2b2"
|
||||
"qbdbqvphsubvplzcnb2md2mq2mw2mvpopcnvpshldvqvpshrdvwhwvpsubuvrangevrcp14vroundsdv"
|
||||
"sm4keyvstmxcsvucomiallwbnoinwrfsbwrgsbc64blcfiblsficmovnendbrenqcmnufdecsfincsfn"
|
||||
"stefrndfsincfucomfyl2xincsspqinvlinvlpinvpcinvvpmcommmovq2pavgupfcmpepfpnaptwris"
|
||||
"eamoseamrsyscsysretdpbutlbsyvaesivaligvandnvcomivfrczvhadvhsubvmclevmgexvmmcvmov"
|
||||
"avmovuvmptvmwrivpandvpextrwvpinsvpmaxvpminvprolvprorvpsadvpsigvpslvpsllvpsravpsr"
|
||||
"lvsqrvtes";
|
||||
|
||||
|
||||
const uint32_t InstDB::_instNameIndexTable[] = {
|
||||
0x80000000, // Small ''.
|
||||
0x80000421, // Small 'aaa'.
|
||||
@@ -4664,65 +4705,6 @@ const uint32_t InstDB::_instNameIndexTable[] = {
|
||||
0x101585A8, // Large 'xsusldtr|k'.
|
||||
0x81499698 // Small 'xtest'.
|
||||
};
|
||||
|
||||
const char InstDB::_instNameStringTable[] =
|
||||
"vgf2p8affineinvqbvaeskeygenassistvbroadcastf32x464x264x4i32x2i32x4i32x8i64x2i64x"
|
||||
"4vpbroadcastmb2w2dvbcstnebf162p128i128vcvtne2ps2vcvtneebf16vcvtneobf16vfmaddsub1"
|
||||
"32ph213pd213ph213ps231pd231ph231psvfmsubadd132vpmultishiftvscatterpf0dqpdqps1dpd"
|
||||
"1dps1qpd1qpsvcvtneps2vextracvextractfvgatherpf0vp2intersecttcmmimfp16tcmmrlfp16s"
|
||||
"h2pssdph2psvfnmadd132213sd213sh213ss231sd231sh231ssvfnmsub132vinservinsertfvpshu"
|
||||
"fbitqvsha512rndprefetchitntawt1saveprevsssha256rndtileloaddtilereleavaesdeclvaes"
|
||||
"enclvcompressvcvttpd2uqqvcvttph2uvcvttps2uvcvttsd2uvcvttsh2uvcvttss2uvfixupimmvf"
|
||||
"madd132vfmsub132vmaskmovdqvpcompressvpconflictvphminposuvpmadd52hluqvpscatterqdv"
|
||||
"punpckhqlqdqvrndscalemsg1msg2clflushopcmpnbexcmpnlexcmpxchg16t0t2tilestorev4fnma"
|
||||
"ddssvcvtpd2uvcvtph2psudqvcvtps2phvcvtsd2uvcvtsh2uvcvtss2uvcvtudq2vcvtuqq2vcvtusi"
|
||||
"2vfcmaddcvfpclassvgetmanmulbvp4dpwssvpclmuvpcmpestrvpcmpistrvperm2fvpermil2vpgat"
|
||||
"hervpmacssdqvpmadcsswubswvpmaskmovpternlogbwwdlbwldqlwdvrsqrt1428pd28ps28sd28ssv"
|
||||
"shufvshuffvzeroupxsaveoptcmpbexcmplexcmpnbxcmpnlxcmpnoxcmpnpxcmpnsxcmpnzx8bfxrst"
|
||||
"orldtilecfmovdir64pvalidarmpadjurmpupdaserialisha1nexsha1rndssttilecftdpbf16tdpf"
|
||||
"p16v4fmadvaddsubvblendmvpdvcvtdq2uwvcvtqq2vcvtsi2vcvtuwvdbpsadvdpbf16vexpanvfcmu"
|
||||
"lccphcshvgetexpvmovdqau16u32u64vmovmskvmovntvmovshdvmovsldvpackssdwbvpackuswbvpb"
|
||||
"lendmdvpdpbssudsvpdpbusvpdpwssvpdpwus2pdvpermtvpexpanvphaddubwqdqhvpmovmskvpmovs"
|
||||
"xbvpmovusqwvpmovzxbvpmulhrvptestnmqvreducevscalefvsm3rndvsm4rndsvunpckhlpdlpsxre"
|
||||
"sldtrs64xsusldtrcldemoclrssbscmpbxcmplxcmpoxcmppxcmpsxcmpzxcvtpifcmovfxsavekorte"
|
||||
"stkshiftrbkunpckmonitorpfrcpipfrsqirtvrdfsbrdgsbsspseamcalsenduisetssbssysesysex"
|
||||
"vcvtwvfmulvldmxcsvmlaundupu8vmovhvmovlhvmpsadvmresumvpadduvpaligngtbgtdgtqgtw2b2"
|
||||
"qbdbqvphsubvplzcnb2md2mq2mw2mvpopcnvpshldvqvpshrdvwhwvpsubuvrangevrcp14vroundsdv"
|
||||
"sm4keyvstmxcsvucomiallwbnoinwrfsbwrgsbc64blcfiblsficmovnendbrenqcmnufdecsfincsfn"
|
||||
"stefrndfsincfucomfyl2xincsspqinvlinvlpinvpcinvvpmcommmovq2pavgupfcmpepfpnaptwris"
|
||||
"eamoseamrsyscsysretdpbutlbsyvaesivaligvandnvcomivfrczvhadvhsubvmclevmgexvmmcvmov"
|
||||
"avmovuvmptvmwrivpandvpextrwvpinsvpmaxvpminvprolvprorvpsadvpsigvpslvpsllvpsravpsr"
|
||||
"lvsqrvtes";
|
||||
|
||||
|
||||
const InstDB::InstNameIndex InstDB::instNameIndex[26] = {
|
||||
{ Inst::kIdAaa , Inst::kIdAxor + 1 },
|
||||
{ Inst::kIdBextr , Inst::kIdBzhi + 1 },
|
||||
{ Inst::kIdCall , Inst::kIdCwde + 1 },
|
||||
{ Inst::kIdDaa , Inst::kIdDpps + 1 },
|
||||
{ Inst::kIdEmms , Inst::kIdExtrq + 1 },
|
||||
{ Inst::kIdF2xm1 , Inst::kIdFyl2xp1 + 1 },
|
||||
{ Inst::kIdGetsec , Inst::kIdGf2p8mulb + 1 },
|
||||
{ Inst::kIdHaddpd , Inst::kIdHsubps + 1 },
|
||||
{ Inst::kIdIdiv , Inst::kIdIretq + 1 },
|
||||
{ Inst::kIdJa , Inst::kIdJz + 1 },
|
||||
{ Inst::kIdKaddb , Inst::kIdKxorw + 1 },
|
||||
{ Inst::kIdLahf , Inst::kIdLzcnt + 1 },
|
||||
{ Inst::kIdMaskmovdqu , Inst::kIdMwaitx + 1 },
|
||||
{ Inst::kIdNeg , Inst::kIdNot + 1 },
|
||||
{ Inst::kIdOr , Inst::kIdOuts + 1 },
|
||||
{ Inst::kIdPabsb , Inst::kIdPxor + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdRcl , Inst::kIdRstorssp + 1 },
|
||||
{ Inst::kIdSahf , Inst::kIdSysretq + 1 },
|
||||
{ Inst::kIdT1mskc , Inst::kIdTzmsk + 1 },
|
||||
{ Inst::kIdUcomisd , Inst::kIdUnpcklps + 1 },
|
||||
{ Inst::kIdV4fmaddps , Inst::kIdVzeroupper + 1 },
|
||||
{ Inst::kIdWbinvd , Inst::kIdWrussq + 1 },
|
||||
{ Inst::kIdXabort , Inst::kIdXtest + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 },
|
||||
{ Inst::kIdNone , Inst::kIdNone + 1 }
|
||||
};
|
||||
// ----------------------------------------------------------------------------
|
||||
// ${NameData:End}
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef ASMJIT_X86_X86INSTDB_P_H_INCLUDED
|
||||
#define ASMJIT_X86_X86INSTDB_P_H_INCLUDED
|
||||
|
||||
#include "../core/instdb_p.h"
|
||||
#include "../x86/x86instdb.h"
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
||||
@@ -201,17 +202,6 @@ struct AdditionalInfo {
|
||||
inline const uint8_t* featuresEnd() const noexcept { return _features + ASMJIT_ARRAY_SIZE(_features); }
|
||||
};
|
||||
|
||||
// ${NameLimits:Begin}
|
||||
// ------------------- Automatically generated, do not edit -------------------
|
||||
enum : uint32_t { kMaxNameSize = 17 };
|
||||
// ----------------------------------------------------------------------------
|
||||
// ${NameLimits:End}
|
||||
|
||||
struct InstNameIndex {
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
struct RWInfo {
|
||||
enum Category : uint8_t {
|
||||
kCategoryGeneric = 0,
|
||||
@@ -297,9 +287,9 @@ extern const uint32_t _mainOpcodeTable[];
|
||||
extern const uint32_t _altOpcodeTable[];
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
extern const uint32_t _instNameIndexTable[];
|
||||
extern const InstNameIndex instNameIndex;
|
||||
extern const char _instNameStringTable[];
|
||||
extern const InstNameIndex instNameIndex[26];
|
||||
extern const uint32_t _instNameIndexTable[];
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
extern const AdditionalInfo _additionalInfoTable[];
|
||||
|
||||
@@ -49,26 +49,26 @@ template<RegType kRegType>
|
||||
struct RegTraits : public BaseRegTraits {};
|
||||
|
||||
//! \cond
|
||||
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
|
||||
// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId |
|
||||
// <--------------------+-----+-------------------------+------------------------+---+---+------------------+
|
||||
ASMJIT_DEFINE_REG_TRAITS(Rip , RegType::kX86_Rip , RegGroup::kX86_Rip , 0 , 1 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(GpbLo, RegType::kX86_GpbLo , RegGroup::kGp , 1 , 16, TypeId::kInt8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(GpbHi, RegType::kX86_GpbHi , RegGroup::kGp , 1 , 4 , TypeId::kInt8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Gpw , RegType::kX86_Gpw , RegGroup::kGp , 2 , 16, TypeId::kInt16 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Gpd , RegType::kX86_Gpd , RegGroup::kGp , 4 , 16, TypeId::kInt32 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Gpq , RegType::kX86_Gpq , RegGroup::kGp , 8 , 16, TypeId::kInt64 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Xmm , RegType::kX86_Xmm , RegGroup::kVec , 16, 32, TypeId::kInt32x4 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Ymm , RegType::kX86_Ymm , RegGroup::kVec , 32, 32, TypeId::kInt32x8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Zmm , RegType::kX86_Zmm , RegGroup::kVec , 64, 32, TypeId::kInt32x16);
|
||||
ASMJIT_DEFINE_REG_TRAITS(KReg , RegType::kX86_KReg , RegGroup::kX86_K , 0 , 8 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Mm , RegType::kX86_Mm , RegGroup::kX86_MM , 8 , 8 , TypeId::kMmx64 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(SReg , RegType::kX86_SReg , RegGroup::kX86_SReg , 2 , 7 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(CReg , RegType::kX86_CReg , RegGroup::kX86_CReg , 0 , 16, TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(DReg , RegType::kX86_DReg , RegGroup::kX86_DReg , 0 , 16, TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(St , RegType::kX86_St , RegGroup::kX86_St , 10, 8 , TypeId::kFloat80 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Bnd , RegType::kX86_Bnd , RegGroup::kX86_Bnd , 16, 4 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(Tmm , RegType::kX86_Tmm , RegGroup::kX86_Tmm , 0 , 8 , TypeId::kVoid );
|
||||
// <--------------------+------------------------+------------------------+---+------------------+
|
||||
// | Reg-Type | Reg-Group |Sz | TypeId |
|
||||
// <--------------------+------------------------+------------------------+---+------------------+
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Rip , RegGroup::kX86_Rip , 0 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_GpbLo , RegGroup::kGp , 1 , TypeId::kInt8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_GpbHi , RegGroup::kGp , 1 , TypeId::kInt8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Gpw , RegGroup::kGp , 2 , TypeId::kInt16 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Gpd , RegGroup::kGp , 4 , TypeId::kInt32 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Gpq , RegGroup::kGp , 8 , TypeId::kInt64 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Xmm , RegGroup::kVec , 16, TypeId::kInt32x4 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Ymm , RegGroup::kVec , 32, TypeId::kInt32x8 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Zmm , RegGroup::kVec , 64, TypeId::kInt32x16);
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_KReg , RegGroup::kX86_K , 0 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Mm , RegGroup::kX86_MM , 8 , TypeId::kMmx64 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_SReg , RegGroup::kX86_SReg , 2 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_CReg , RegGroup::kX86_CReg , 0 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_DReg , RegGroup::kX86_DReg , 0 , TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_St , RegGroup::kX86_St , 10, TypeId::kFloat80 );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Bnd , RegGroup::kX86_Bnd , 16, TypeId::kVoid );
|
||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kX86_Tmm , RegGroup::kX86_Tmm , 0 , TypeId::kVoid );
|
||||
//! \endcond
|
||||
|
||||
//! Register (X86).
|
||||
|
||||
@@ -46,7 +46,7 @@ int main(int argc, char* argv[]) {
|
||||
printf(" --arch=x86 32-bit X86 architecture (X86)\n");
|
||||
printf(" --arch=x64 64-bit X86 architecture (X86_64)\n");
|
||||
#endif
|
||||
#if !defined(ASMJIT_AARCH64)
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
|
||||
#endif
|
||||
printf("\n");
|
||||
@@ -56,7 +56,6 @@ int main(int argc, char* argv[]) {
|
||||
const char* arch = cmdLine.valueOf("--arch", "all");
|
||||
bool x86Failed = false;
|
||||
bool x64Failed = false;
|
||||
bool armFailed = false;
|
||||
bool aarch64Failed = false;
|
||||
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
@@ -72,7 +71,7 @@ int main(int argc, char* argv[]) {
|
||||
aarch64Failed = !testA64Assembler(settings);
|
||||
#endif
|
||||
|
||||
bool failed = x86Failed || x64Failed || armFailed || aarch64Failed;
|
||||
bool failed = x86Failed || x64Failed || aarch64Failed;
|
||||
|
||||
if (failed) {
|
||||
if (x86Failed)
|
||||
@@ -81,9 +80,6 @@ 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");
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
assembler.addDiagnosticOptions(asmjit::DiagnosticOptions::kValidateAssembler);
|
||||
}
|
||||
|
||||
ASMJIT_NOINLINE bool testValidInstruction(const char* s, const char* expectedOpcode, asmjit::Error err) noexcept {
|
||||
ASMJIT_NOINLINE bool testValidInstruction(const char* s, const char* expectedOpcode, asmjit::Error err = asmjit::kErrorOk) noexcept {
|
||||
count++;
|
||||
|
||||
if (err) {
|
||||
|
||||
@@ -64,11 +64,11 @@ public:
|
||||
if (_preserveFP)
|
||||
funcNode->frame().setPreservedFP();
|
||||
|
||||
arm::Gp sum;
|
||||
a64::Gp sum;
|
||||
|
||||
if (argCount) {
|
||||
for (i = 0; i < argCount; i++) {
|
||||
arm::Gp iReg = cc.newInt32("i%u", i);
|
||||
a64::Gp iReg = cc.newInt32("i%u", i);
|
||||
funcNode->setArg(i, iReg);
|
||||
|
||||
if (i == 0)
|
||||
@@ -184,7 +184,7 @@ public:
|
||||
result.assignFormat("ret={%u, %u}", resultRet >> 28, resultRet & 0x0FFFFFFFu);
|
||||
expect.assignFormat("ret={%u, %u}", expectRet >> 28, expectRet & 0x0FFFFFFFu);
|
||||
|
||||
return resultRet == expectRet;
|
||||
return result == expect;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -203,9 +203,9 @@ public:
|
||||
virtual void compile(a64::Compiler& cc) {
|
||||
FuncNode* funcNode = cc.addFunc(FuncSignatureT<void, void*, const void*, const void*>());
|
||||
|
||||
arm::Gp dst = cc.newUIntPtr("dst");
|
||||
arm::Gp src1 = cc.newUIntPtr("src1");
|
||||
arm::Gp src2 = cc.newUIntPtr("src2");
|
||||
a64::Gp dst = cc.newUIntPtr("dst");
|
||||
a64::Gp src1 = cc.newUIntPtr("src1");
|
||||
a64::Gp src2 = cc.newUIntPtr("src2");
|
||||
|
||||
funcNode->setArg(0, dst);
|
||||
funcNode->setArg(1, src1);
|
||||
@@ -215,10 +215,10 @@ public:
|
||||
arm::Vec v2 = cc.newVecQ("vec2");
|
||||
arm::Vec v3 = cc.newVecQ("vec3");
|
||||
|
||||
cc.ldr(v2, arm::ptr(src1));
|
||||
cc.ldr(v3, arm::ptr(src2));
|
||||
cc.ldr(v2, a64::ptr(src1));
|
||||
cc.ldr(v3, a64::ptr(src2));
|
||||
cc.add(v1.b16(), v2.b16(), v3.b16());
|
||||
cc.str(v1, arm::ptr(dst));
|
||||
cc.str(v1, a64::ptr(dst));
|
||||
|
||||
cc.endFunc();
|
||||
}
|
||||
@@ -235,13 +235,10 @@ public:
|
||||
|
||||
ptr_as_func<Func>(_func)(dst, aSrc, bSrc);
|
||||
|
||||
unsigned int resultRet = 0;
|
||||
unsigned int expectRet = 0;
|
||||
|
||||
result.assignFormat("ret={%u, %u, %u, %u}", dst[0], dst[1], dst[2], dst[3]);
|
||||
expect.assignFormat("ret={%u, %u, %u, %u}", ref[0], ref[1], ref[2], ref[3]);
|
||||
|
||||
return resultRet == expectRet;
|
||||
return result == expect;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -266,14 +263,14 @@ public:
|
||||
virtual void compile(a64::Compiler& cc) {
|
||||
cc.addFunc(FuncSignatureT<int>());
|
||||
|
||||
arm::Gp* regs = static_cast<arm::Gp*>(malloc(_regCount * sizeof(arm::Gp)));
|
||||
a64::Gp* regs = static_cast<a64::Gp*>(malloc(_regCount * sizeof(a64::Gp)));
|
||||
|
||||
for (uint32_t i = 0; i < _regCount; i++) {
|
||||
regs[i] = cc.newUInt32("reg%u", i);
|
||||
cc.mov(regs[i], i + 1);
|
||||
}
|
||||
|
||||
arm::Gp sum = cc.newUInt32("sum");
|
||||
a64::Gp sum = cc.newUInt32("sum");
|
||||
cc.mov(sum, 0);
|
||||
|
||||
for (uint32_t i = 0; i < _regCount; i++) {
|
||||
@@ -316,13 +313,13 @@ public:
|
||||
virtual void compile(a64::Compiler& cc) {
|
||||
cc.addFunc(FuncSignatureT<int>());
|
||||
|
||||
arm::Gp addr = cc.newIntPtr("addr");
|
||||
arm::Gp val = cc.newIntPtr("val");
|
||||
a64::Gp addr = cc.newIntPtr("addr");
|
||||
a64::Gp val = cc.newIntPtr("val");
|
||||
|
||||
Label L_Table = cc.newLabel();
|
||||
|
||||
cc.adr(addr, L_Table);
|
||||
cc.ldrsw(val, arm::ptr(addr, 8));
|
||||
cc.ldrsw(val, a64::ptr(addr, 8));
|
||||
cc.ret(val);
|
||||
cc.endFunc();
|
||||
|
||||
@@ -360,9 +357,9 @@ public:
|
||||
virtual void compile(a64::Compiler& cc) {
|
||||
FuncNode* funcNode = cc.addFunc(FuncSignatureT<void, void*, size_t>());
|
||||
|
||||
arm::Gp p = cc.newIntPtr("p");
|
||||
arm::Gp count = cc.newIntPtr("count");
|
||||
arm::Gp i = cc.newIntPtr("i");
|
||||
a64::Gp p = cc.newIntPtr("p");
|
||||
a64::Gp count = cc.newIntPtr("count");
|
||||
a64::Gp i = cc.newIntPtr("i");
|
||||
Label L = cc.newLabel();
|
||||
|
||||
funcNode->setArg(0, p);
|
||||
@@ -415,10 +412,10 @@ public:
|
||||
virtual void compile(a64::Compiler& cc) {
|
||||
FuncNode* funcNode = cc.addFunc(FuncSignatureT<uint32_t, uint32_t, uint32_t>());
|
||||
|
||||
arm::Gp x = cc.newUInt32("x");
|
||||
arm::Gp y = cc.newUInt32("y");
|
||||
arm::Gp r = cc.newUInt32("r");
|
||||
arm::Gp fn = cc.newUIntPtr("fn");
|
||||
a64::Gp x = cc.newUInt32("x");
|
||||
a64::Gp y = cc.newUInt32("y");
|
||||
a64::Gp r = cc.newUInt32("r");
|
||||
a64::Gp fn = cc.newUIntPtr("fn");
|
||||
|
||||
funcNode->setArg(0, x);
|
||||
funcNode->setArg(1, y);
|
||||
@@ -471,7 +468,7 @@ public:
|
||||
arm::Vec x = cc.newVecD("x");
|
||||
arm::Vec y = cc.newVecD("y");
|
||||
arm::Vec r = cc.newVecD("r");
|
||||
arm::Gp fn = cc.newUIntPtr("fn");
|
||||
a64::Gp fn = cc.newUIntPtr("fn");
|
||||
|
||||
funcNode->setArg(0, x);
|
||||
funcNode->setArg(1, y);
|
||||
@@ -523,7 +520,7 @@ public:
|
||||
arm::Vec x = cc.newVecD("x");
|
||||
arm::Vec y = cc.newVecD("y");
|
||||
arm::Vec r = cc.newVecD("r");
|
||||
arm::Gp fn = cc.newUIntPtr("fn");
|
||||
a64::Gp fn = cc.newUIntPtr("fn");
|
||||
|
||||
funcNode->setArg(0, x);
|
||||
funcNode->setArg(1, y);
|
||||
@@ -587,10 +584,10 @@ public:
|
||||
|
||||
arm::Vec a = cc.newVecS("a");
|
||||
arm::Vec b = cc.newVecS("b");
|
||||
arm::Gp op = cc.newUInt32("op");
|
||||
a64::Gp op = cc.newUInt32("op");
|
||||
|
||||
arm::Gp target = cc.newIntPtr("target");
|
||||
arm::Gp offset = cc.newIntPtr("offset");
|
||||
a64::Gp target = cc.newIntPtr("target");
|
||||
a64::Gp offset = cc.newIntPtr("offset");
|
||||
|
||||
Label L_End = cc.newLabel();
|
||||
|
||||
@@ -605,7 +602,7 @@ public:
|
||||
funcNode->setArg(2, op);
|
||||
|
||||
cc.adr(target, L_Table);
|
||||
cc.ldrsw(offset, arm::ptr(target, op, arm::sxtw(2)));
|
||||
cc.ldrsw(offset, a64::ptr(target, op, a64::sxtw(2)));
|
||||
cc.add(target, target, offset);
|
||||
|
||||
// JumpAnnotation allows to annotate all possible jump targets of
|
||||
|
||||
@@ -40,7 +40,7 @@ int main(int argc, char* argv[]) {
|
||||
printf(" --arch=x86 32-bit X86 architecture (X86)\n");
|
||||
printf(" --arch=x64 64-bit X86 architecture (X86_64)\n");
|
||||
#endif
|
||||
#if !defined(ASMJIT_AARCH64)
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace {
|
||||
|
||||
ASMJIT_MAYBE_UNUSED
|
||||
const char* asmjitArchAsString(asmjit::Arch arch) noexcept {
|
||||
static inline const char* asmjitArchAsString(asmjit::Arch arch) noexcept {
|
||||
switch (arch) {
|
||||
case asmjit::Arch::kX86 : return "X86";
|
||||
case asmjit::Arch::kX64 : return "X64";
|
||||
@@ -39,7 +39,7 @@ const char* asmjitArchAsString(asmjit::Arch arch) noexcept {
|
||||
}
|
||||
|
||||
ASMJIT_MAYBE_UNUSED
|
||||
void printIndented(const char* str, size_t indent) noexcept {
|
||||
static inline void printIndented(const char* str, size_t indent) noexcept {
|
||||
const char* start = str;
|
||||
while (*str) {
|
||||
if (*str == '\n') {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// 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;
|
||||
592
tools/generator-commons.js
Normal file
592
tools/generator-commons.js
Normal file
@@ -0,0 +1,592 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
function nop(x) { return x; }
|
||||
|
||||
// Generator - Constants
|
||||
// ---------------------
|
||||
|
||||
const kIndent = " ";
|
||||
exports.kIndent = kIndent;
|
||||
|
||||
const kLineWidth = 120;
|
||||
|
||||
// Generator - Logging
|
||||
// -------------------
|
||||
|
||||
let VERBOSE = false;
|
||||
|
||||
function setDebugVerbosity(value) {
|
||||
VERBOSE = value;
|
||||
}
|
||||
exports.setDebugVerbosity = setDebugVerbosity;
|
||||
|
||||
function DEBUG(msg) {
|
||||
if (VERBOSE)
|
||||
console.log(msg);
|
||||
}
|
||||
exports.DEBUG = DEBUG;
|
||||
|
||||
function WARN(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
exports.WARN = WARN;
|
||||
|
||||
function FATAL(msg) {
|
||||
console.log(`FATAL: ${msg}`);
|
||||
throw new Error(msg);
|
||||
}
|
||||
exports.FATAL = FATAL;
|
||||
|
||||
// Generator - Object Utilities
|
||||
// ----------------------------
|
||||
|
||||
class ObjectUtils {
|
||||
static clone(map) {
|
||||
return Object.assign(Object.create(null), map);
|
||||
}
|
||||
|
||||
static merge(a, b) {
|
||||
if (a === b)
|
||||
return a;
|
||||
|
||||
for (let k in b) {
|
||||
let av = a[k];
|
||||
let bv = b[k];
|
||||
|
||||
if (typeof av === "object" && typeof bv === "object")
|
||||
ObjectUtils.merge(av, bv);
|
||||
else
|
||||
a[k] = bv;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static equals(a, b) {
|
||||
if (a === b)
|
||||
return true;
|
||||
|
||||
if (typeof a !== typeof b)
|
||||
return false;
|
||||
|
||||
if (typeof a !== "object")
|
||||
return a === b;
|
||||
|
||||
if (Array.isArray(a) || Array.isArray(b)) {
|
||||
if (Array.isArray(a) !== Array.isArray(b))
|
||||
return false;
|
||||
|
||||
const len = a.length;
|
||||
if (b.length !== len)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < len; i++)
|
||||
if (!ObjectUtils.equals(a[i], b[i]))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (a === null || b === null)
|
||||
return a === b;
|
||||
|
||||
for (let k in a)
|
||||
if (!hasOwn.call(b, k) || !ObjectUtils.equals(a[k], b[k]))
|
||||
return false;
|
||||
|
||||
for (let k in b)
|
||||
if (!hasOwn.call(a, k))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static equalsExcept(a, b, except) {
|
||||
if (a === b)
|
||||
return true;
|
||||
|
||||
if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b))
|
||||
return ObjectUtils.equals(a, b);
|
||||
|
||||
for (let k in a)
|
||||
if (!hasOwn.call(except, k) && (!hasOwn.call(b, k) || !ObjectUtils.equals(a[k], b[k])))
|
||||
return false;
|
||||
|
||||
for (let k in b)
|
||||
if (!hasOwn.call(except, k) && !hasOwn.call(a, k))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static findKey(map, keys) {
|
||||
for (let key in keys)
|
||||
if (hasOwn.call(map, key))
|
||||
return key;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static hasAny(map, keys) {
|
||||
for (let key in keys)
|
||||
if (hasOwn.call(map, key))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static and(a, b) {
|
||||
const out = Object.create(null);
|
||||
for (let k in a)
|
||||
if (hasOwn.call(b, k))
|
||||
out[k] = true;
|
||||
return out;
|
||||
}
|
||||
|
||||
static xor(a, b) {
|
||||
const out = Object.create(null);
|
||||
for (let k in a) if (!hasOwn.call(b, k)) out[k] = true;
|
||||
for (let k in b) if (!hasOwn.call(a, k)) out[k] = true;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
exports.ObjectUtils = ObjectUtils;
|
||||
|
||||
// Generator - Array Utilities
|
||||
// ---------------------------
|
||||
|
||||
class ArrayUtils {
|
||||
static min(arr, fn) {
|
||||
if (!arr.length)
|
||||
return null;
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
let v = fn(arr[0]);
|
||||
for (let i = 1; i < arr.length; i++)
|
||||
v = Math.min(v, fn(arr[i]));
|
||||
return v;
|
||||
}
|
||||
|
||||
static max(arr, fn) {
|
||||
if (!arr.length)
|
||||
return null;
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
let v = fn(arr[0]);
|
||||
for (let i = 1; i < arr.length; i++)
|
||||
v = Math.max(v, fn(arr[i]));
|
||||
return v;
|
||||
}
|
||||
|
||||
static sorted(obj, cmp) {
|
||||
const out = Array.isArray(obj) ? obj.slice() : Object.getOwnPropertyNames(obj);
|
||||
out.sort(cmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
static deepIndexOf(arr, what) {
|
||||
for (let i = 0; i < arr.length; i++)
|
||||
if (ObjectUtils.equals(arr[i], what))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static toDict(arr, value) {
|
||||
if (value === undefined)
|
||||
value = true;
|
||||
|
||||
const out = Object.create(null);
|
||||
for (let i = 0; i < arr.length; i++)
|
||||
out[arr[i]] = value;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
exports.ArrayUtils = ArrayUtils;
|
||||
|
||||
|
||||
// Generator - String Utilities
|
||||
// ----------------------------
|
||||
|
||||
class StringUtils {
|
||||
static asString(x) { return String(x); }
|
||||
|
||||
static countOf(s, pattern) {
|
||||
if (!pattern)
|
||||
FATAL(`Pattern cannot be empty`);
|
||||
|
||||
let n = 0;
|
||||
let pos = 0;
|
||||
|
||||
while ((pos = s.indexOf(pattern, pos)) >= 0) {
|
||||
n++;
|
||||
pos += pattern.length;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static trimLeft(s) { return s.replace(/^\s+/, ""); }
|
||||
static trimRight(s) { return s.replace(/\s+$/, ""); }
|
||||
|
||||
static upFirst(s) {
|
||||
if (!s) return "";
|
||||
return s[0].toUpperCase() + s.substr(1);
|
||||
}
|
||||
|
||||
static decToHex(n, nPad) {
|
||||
let hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
|
||||
while (nPad > hex.length)
|
||||
hex = "0" + hex;
|
||||
return "0x" + hex.toUpperCase();
|
||||
}
|
||||
|
||||
static format(array, indent, showIndex, mapFn) {
|
||||
if (!mapFn)
|
||||
mapFn = StringUtils.asString;
|
||||
|
||||
let s = "";
|
||||
let threshold = 80;
|
||||
|
||||
if (showIndex === -1)
|
||||
s += indent;
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const last = i === array.length - 1;
|
||||
|
||||
if (showIndex !== -1)
|
||||
s += indent;
|
||||
|
||||
s += mapFn(item);
|
||||
if (showIndex > 0) {
|
||||
s += `${last ? " " : ","} // #${i}`;
|
||||
if (typeof array.refCountOf === "function")
|
||||
s += ` [ref=${array.refCountOf(item)}x]`;
|
||||
}
|
||||
else if (!last) {
|
||||
s += ",";
|
||||
}
|
||||
|
||||
if (showIndex === -1) {
|
||||
if (s.length >= threshold - 1 && !last) {
|
||||
s += "\n" + indent;
|
||||
threshold += 80;
|
||||
}
|
||||
else {
|
||||
if (!last) s += " ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!last) s += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static makeCxxArray(array, code, indent) {
|
||||
if (typeof indent !== "string")
|
||||
indent = kIndent;
|
||||
|
||||
return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`;
|
||||
}
|
||||
|
||||
static makeCxxArrayWithComment(array, code, indent) {
|
||||
if (typeof indent !== "string")
|
||||
indent = kIndent;
|
||||
|
||||
let s = "";
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const last = i === array.length - 1;
|
||||
s += indent + array[i].data +
|
||||
(last ? " // " : ", // ") + (array[i].refs ? "#" + String(i) : "").padEnd(5) + array[i].comment + "\n";
|
||||
}
|
||||
return `${code} = {\n${s}};\n`;
|
||||
}
|
||||
|
||||
static formatCppStruct(...args) {
|
||||
return "{ " + args.join(", ") + " }";
|
||||
}
|
||||
|
||||
static formatCppFlags(obj, fn, none) {
|
||||
if (none == null)
|
||||
none = "0";
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
let out = "";
|
||||
for (let k in obj) {
|
||||
if (obj[k])
|
||||
out += (out ? " | " : "") + fn(k);
|
||||
}
|
||||
return out ? out : none;
|
||||
}
|
||||
|
||||
static formatRecords(array, indent, fn) {
|
||||
if (typeof indent !== "string")
|
||||
indent = kIndent;
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
let s = "";
|
||||
let line = "";
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = fn(array[i]);
|
||||
const combined = line ? line + ", " + item : item;
|
||||
|
||||
if (combined.length >= kLineWidth) {
|
||||
s = s ? s + ",\n" + line : line;
|
||||
line = item;
|
||||
}
|
||||
else {
|
||||
line = combined;
|
||||
}
|
||||
}
|
||||
|
||||
if (line) {
|
||||
s = s ? s + ",\n" + line : line;
|
||||
}
|
||||
|
||||
return StringUtils.indent(s, indent);
|
||||
}
|
||||
|
||||
static disclaimer(s) {
|
||||
return "// ------------------- Automatically generated, do not edit -------------------\n" +
|
||||
s +
|
||||
"// ----------------------------------------------------------------------------\n";
|
||||
}
|
||||
|
||||
static indent(s, indentation) {
|
||||
if (typeof indentation === "number")
|
||||
indentation = " ".repeat(indentation);
|
||||
|
||||
let lines = s.split(/\r?\n/g);
|
||||
if (indentation) {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
if (line)
|
||||
lines[i] = indentation + line;
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
static extract(s, start, end) {
|
||||
const iStart = s.indexOf(start);
|
||||
const iEnd = s.indexOf(end);
|
||||
|
||||
if (iStart === -1)
|
||||
FATAL(`StringUtils.extract(): Couldn't locate start mark '${start}'`);
|
||||
|
||||
if (iEnd === -1)
|
||||
FATAL(`StringUtils.extract(): Couldn't locate end mark '${end}'`);
|
||||
|
||||
return s.substring(iStart + start.length, iEnd).trim();
|
||||
}
|
||||
|
||||
static inject(s, start, end, code) {
|
||||
let iStart = s.indexOf(start);
|
||||
let iEnd = s.indexOf(end);
|
||||
|
||||
if (iStart === -1)
|
||||
FATAL(`StringUtils.inject(): Couldn't locate start mark '${start}'`);
|
||||
|
||||
if (iEnd === -1)
|
||||
FATAL(`StringUtils.inject(): Couldn't locate end mark '${end}'`);
|
||||
|
||||
let nIndent = 0;
|
||||
while (iStart > 0 && s[iStart-1] === " ") {
|
||||
iStart--;
|
||||
nIndent++;
|
||||
}
|
||||
|
||||
if (nIndent) {
|
||||
const indentation = " ".repeat(nIndent);
|
||||
code = StringUtils.indent(code, indentation) + indentation;
|
||||
}
|
||||
|
||||
return s.substr(0, iStart + start.length + nIndent) + code + s.substr(iEnd);
|
||||
}
|
||||
|
||||
static makePriorityCompare(priorityArray) {
|
||||
const map = Object.create(null);
|
||||
priorityArray.forEach((str, index) => { map[str] = index; });
|
||||
|
||||
return function(a, b) {
|
||||
const ax = hasOwn.call(map, a) ? map[a] : Infinity;
|
||||
const bx = hasOwn.call(map, b) ? map[b] : Infinity;
|
||||
return ax != bx ? ax - bx : a < b ? -1 : a > b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.StringUtils = StringUtils;
|
||||
|
||||
// Generator - Indexed Array
|
||||
// =========================
|
||||
|
||||
// IndexedArray is an Array replacement that allows to index each item inserted to it. Its main purpose
|
||||
// is to avoid data duplication, if an item passed to `addIndexed()` is already within the Array then
|
||||
// it's not inserted and the existing index is returned instead.
|
||||
function IndexedArray_keyOf(item) {
|
||||
return typeof item === "string" ? item : JSON.stringify(item);
|
||||
}
|
||||
|
||||
class IndexedArray extends Array {
|
||||
constructor() {
|
||||
super();
|
||||
this._index = Object.create(null);
|
||||
}
|
||||
|
||||
refCountOf(item) {
|
||||
const key = IndexedArray_keyOf(item);
|
||||
const idx = this._index[key];
|
||||
|
||||
return idx !== undefined ? idx.refCount : 0;
|
||||
}
|
||||
|
||||
addIndexed(item) {
|
||||
const key = IndexedArray_keyOf(item);
|
||||
let idx = this._index[key];
|
||||
|
||||
if (idx !== undefined) {
|
||||
idx.refCount++;
|
||||
return idx.data;
|
||||
}
|
||||
|
||||
idx = this.length;
|
||||
this._index[key] = {
|
||||
data: idx,
|
||||
refCount: 1
|
||||
};
|
||||
this.push(item);
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
exports.IndexedArray = IndexedArray;
|
||||
|
||||
// Generator - Indexed String
|
||||
// ==========================
|
||||
|
||||
// IndexedString is mostly used to merge all instruction names into a single string with external
|
||||
// index. It's designed mostly for generating C++ tables. Consider the following cases in C++:
|
||||
//
|
||||
// a) static const char* const* instNames = { "add", "mov", "vpunpcklbw" };
|
||||
//
|
||||
// b) static const char instNames[] = { "add\0" "mov\0" "vpunpcklbw\0" };
|
||||
// static const uint16_t instNameIndex[] = { 0, 4, 8 };
|
||||
//
|
||||
// The latter (b) has an advantage that it doesn't have to be relocated by the linker, which saves
|
||||
// a lot of space in the resulting binary and a lot of CPU cycles (and memory) when the linker loads
|
||||
// it. AsmJit supports thousands of instructions so each optimization like this makes it smaller and
|
||||
// faster to load.
|
||||
class IndexedString {
|
||||
constructor() {
|
||||
this.map = Object.create(null);
|
||||
this.array = [];
|
||||
this.size = -1;
|
||||
}
|
||||
|
||||
add(s) {
|
||||
this.map[s] = -1;
|
||||
}
|
||||
|
||||
index() {
|
||||
const map = this.map;
|
||||
const array = this.array;
|
||||
const partialMap = Object.create(null);
|
||||
|
||||
let k, kp;
|
||||
let i, len;
|
||||
|
||||
// Create a map that will contain all keys and partial keys.
|
||||
for (k in map) {
|
||||
if (!k) {
|
||||
partialMap[k] = k;
|
||||
}
|
||||
else {
|
||||
for (i = 0, len = k.length; i < len; i++) {
|
||||
kp = k.substr(i);
|
||||
if (!hasOwn.call(partialMap, kp) || partialMap[kp].length < len)
|
||||
partialMap[kp] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array that will only contain keys that are needed.
|
||||
for (k in map)
|
||||
if (partialMap[k] === k)
|
||||
array.push(k);
|
||||
array.sort();
|
||||
|
||||
// Create valid offsets to the `array`.
|
||||
let offMap = Object.create(null);
|
||||
let offset = 0;
|
||||
|
||||
for (i = 0, len = array.length; i < len; i++) {
|
||||
k = array[i];
|
||||
|
||||
offMap[k] = offset;
|
||||
offset += k.length + 1;
|
||||
}
|
||||
this.size = offset;
|
||||
|
||||
// Assign valid offsets to `map`.
|
||||
for (kp in map) {
|
||||
k = partialMap[kp];
|
||||
map[kp] = offMap[k] + k.length - kp.length;
|
||||
}
|
||||
}
|
||||
|
||||
format(indent, justify) {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.format(): not indexed yet, call index()`);
|
||||
|
||||
const array = this.array;
|
||||
if (!justify) justify = 0;
|
||||
|
||||
let i;
|
||||
let s = "";
|
||||
let line = "";
|
||||
|
||||
for (i = 0; i < array.length; i++) {
|
||||
const item = "\"" + array[i] + ((i !== array.length - 1) ? "\\0\"" : "\";");
|
||||
const newl = line + (line ? " " : indent) + item;
|
||||
|
||||
if (newl.length <= justify) {
|
||||
line = newl;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
s += line + "\n";
|
||||
line = indent + item;
|
||||
}
|
||||
}
|
||||
|
||||
return s + line;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.getSize(): Not indexed yet, call index()`);
|
||||
return this.size;
|
||||
}
|
||||
|
||||
getIndex(k) {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.getIndex(): Not indexed yet, call index()`);
|
||||
|
||||
if (!hasOwn.call(this.map, k))
|
||||
FATAL(`IndexedString.getIndex(): Key '${k}' not found.`);
|
||||
|
||||
return this.map[k];
|
||||
}
|
||||
}
|
||||
exports.IndexedString = IndexedString;
|
||||
@@ -4,7 +4,7 @@
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
// C++ code generation helpers.
|
||||
const commons = require("./gencommons.js");
|
||||
const commons = require("./generator-commons.js");
|
||||
const FATAL = commons.FATAL;
|
||||
|
||||
// Utilities to convert primitives to C++ code.
|
||||
@@ -6,13 +6,13 @@
|
||||
"use strict";
|
||||
|
||||
const core = require("./tablegen.js");
|
||||
const commons = require("./gencommons.js");
|
||||
const commons = require("./generator-commons.js");
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
const asmdb = core.asmdb;
|
||||
const kIndent = core.kIndent;
|
||||
const IndexedArray = core.IndexedArray;
|
||||
const StringUtils = core.StringUtils;
|
||||
const kIndent = commons.kIndent;
|
||||
const IndexedArray = commons.IndexedArray;
|
||||
const StringUtils = commons.StringUtils;
|
||||
|
||||
const FATAL = commons.FATAL;
|
||||
|
||||
@@ -20,13 +20,10 @@ const FATAL = commons.FATAL;
|
||||
// [ArmDB]
|
||||
// ============================================================================
|
||||
|
||||
// Create ARM ISA.
|
||||
const isa = new asmdb.arm.ISA();
|
||||
|
||||
// ============================================================================
|
||||
// [tablegen.arm.GenUtils]
|
||||
// ============================================================================
|
||||
// Create AArch64 ISA.
|
||||
const isa = new asmdb.aarch64.ISA();
|
||||
|
||||
/*
|
||||
class GenUtils {
|
||||
// Get a list of instructions based on `name` and optional `mode`.
|
||||
static query(name, mode) {
|
||||
@@ -71,6 +68,7 @@ class GenUtils {
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// [tablegen.arm.ArmTableGen]
|
||||
|
||||
@@ -8,25 +8,22 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const cxx = require("./gencxx.js");
|
||||
const commons = require("./gencommons.js");
|
||||
const commons = require("./generator-commons.js");
|
||||
const cxx = require("./generator-cxx.js");
|
||||
const core = require("./tablegen.js");
|
||||
|
||||
const asmdb = core.asmdb;
|
||||
const kIndent = core.kIndent;
|
||||
|
||||
const Lang = core.Lang;
|
||||
const CxxUtils = core.CxxUtils;
|
||||
const MapUtils = core.MapUtils;
|
||||
const ArrayUtils = core.ArrayUtils;
|
||||
const StringUtils = core.StringUtils;
|
||||
const IndexedArray = core.IndexedArray;
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
const disclaimer = StringUtils.disclaimer;
|
||||
|
||||
const DEBUG = commons.DEBUG;
|
||||
const FATAL = commons.FATAL;
|
||||
const kIndent = commons.kIndent;
|
||||
const ArrayUtils = commons.ArrayUtils;
|
||||
const IndexedArray = commons.IndexedArray;
|
||||
const ObjectUtils = commons.ObjectUtils;
|
||||
const StringUtils = commons.StringUtils;
|
||||
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
const disclaimer = StringUtils.disclaimer;
|
||||
|
||||
const decToHex = StringUtils.decToHex;
|
||||
|
||||
@@ -37,10 +34,6 @@ function readJSON(fileName) {
|
||||
|
||||
const x86data = readJSON(path.join(__dirname, "..", "db", asmdb.x86.dbName));
|
||||
|
||||
// TODO: Fix these regressions:
|
||||
// cvtsi2ss
|
||||
// enqcmd
|
||||
|
||||
// ============================================================================
|
||||
// [tablegen.x86.x86isa]
|
||||
// ============================================================================
|
||||
@@ -559,7 +552,7 @@ class X86TableGen extends core.TableGen {
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
printMissing() {
|
||||
const ignored = MapUtils.arrayToMap([
|
||||
const ignored = ArrayUtils.toDict([
|
||||
"cmpsb", "cmpsw", "cmpsd", "cmpsq",
|
||||
"lodsb", "lodsw", "lodsd", "lodsq",
|
||||
"movsb", "movsw", "movsd", "movsq",
|
||||
@@ -994,8 +987,8 @@ class AltOpcodeTable extends core.Task {
|
||||
// [tablegen.x86.InstSignatureTable]
|
||||
// ============================================================================
|
||||
|
||||
const RegOp = MapUtils.arrayToMap(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
|
||||
const MemOp = MapUtils.arrayToMap(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
|
||||
const RegOp = ArrayUtils.toDict(["al", "ah", "ax", "eax", "rax", "cl", "r8lo", "r8hi", "r16", "r32", "r64", "xmm", "ymm", "zmm", "mm", "k", "sreg", "creg", "dreg", "st", "bnd"]);
|
||||
const MemOp = ArrayUtils.toDict(["m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"]);
|
||||
|
||||
const cmpOp = StringUtils.makePriorityCompare([
|
||||
"RegGpbLo", "RegGpbHi", "RegGpw", "RegGpd", "RegGpq", "RegXmm", "RegYmm", "RegZmm", "RegMm", "RegKReg", "RegSReg", "RegCReg", "RegDReg", "RegSt", "RegBnd", "RegTmm",
|
||||
@@ -1034,11 +1027,11 @@ class OSignature {
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return MapUtils.equals(this.flags, other.flags);
|
||||
return ObjectUtils.equals(this.flags, other.flags);
|
||||
}
|
||||
|
||||
xor(other) {
|
||||
const result = MapUtils.xor(this.flags, other.flags);
|
||||
const result = ObjectUtils.xor(this.flags, other.flags);
|
||||
return Object.getOwnPropertyNames(result).length === 0 ? null : result;
|
||||
}
|
||||
|
||||
@@ -1286,7 +1279,7 @@ class SignatureArray extends Array {
|
||||
for (var i = 0; i < inst.length; i++) {
|
||||
const op = inst[i];
|
||||
if (regOps & (1 << i))
|
||||
s += "{" + ArrayUtils.sorted(MapUtils.and(op.flags, RegOp)).join("|") + "}";
|
||||
s += "{" + ArrayUtils.sorted(ObjectUtils.and(op.flags, RegOp)).join("|") + "}";
|
||||
}
|
||||
return s || "?";
|
||||
}
|
||||
@@ -1305,7 +1298,7 @@ class SignatureArray extends Array {
|
||||
// Check if this instruction signature has a memory operand of explicit size.
|
||||
for (i = 0; i < len; i++) {
|
||||
const aOp = aInst[i];
|
||||
const mem = MapUtils.firstOf(aOp.flags, MemOp);
|
||||
const mem = ObjectUtils.findKey(aOp.flags, MemOp);
|
||||
|
||||
if (mem) {
|
||||
// Stop if the memory operand has implicit-size or if there is more than one.
|
||||
@@ -1318,7 +1311,7 @@ class SignatureArray extends Array {
|
||||
memPos = i;
|
||||
}
|
||||
}
|
||||
else if (MapUtils.anyOf(aOp.flags, RegOp)) {
|
||||
else if (ObjectUtils.hasAny(aOp.flags, RegOp)) {
|
||||
// Doesn't consider 'r/m' as we already checked 'm'.
|
||||
regOps |= (1 << i);
|
||||
}
|
||||
@@ -1343,7 +1336,7 @@ class SignatureArray extends Array {
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i === memPos) continue;
|
||||
|
||||
const reg = MapUtils.anyOf(bInst[i].flags, RegOp);
|
||||
const reg = ObjectUtils.hasAny(bInst[i].flags, RegOp);
|
||||
if (regOps & (1 << i))
|
||||
hasMatch &= reg;
|
||||
else if (reg)
|
||||
@@ -1354,7 +1347,7 @@ class SignatureArray extends Array {
|
||||
const bOp = bInst[memPos];
|
||||
if (bOp.flags.mem) continue;
|
||||
|
||||
const mem = MapUtils.firstOf(bOp.flags, MemOp);
|
||||
const mem = ObjectUtils.findKey(bOp.flags, MemOp);
|
||||
if (mem === memOp) {
|
||||
sameSizeSet.push(bInst);
|
||||
}
|
||||
@@ -1816,7 +1809,7 @@ class AdditionalInfoTable extends core.Task {
|
||||
break;
|
||||
}
|
||||
|
||||
const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + CxxUtils.flags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")");
|
||||
const instFlagsIndex = instFlagsTable.addIndexed("InstRWFlags(" + StringUtils.formatCppFlags(instFlags, (f) => { return `FLAG(${f})`; }, "FLAG(None)") + ")");
|
||||
const rwInfoIndex = rwInfoTable.addIndexed(`{ ${rData}, ${wData} }`);
|
||||
|
||||
inst.additionalInfoIndex = additionaInfoTable.addIndexed(`{ ${instFlagsIndex}, ${rwInfoIndex}, { ${features} } }`);
|
||||
@@ -1901,7 +1894,7 @@ class AdditionalInfoTable extends core.Task {
|
||||
// [tablegen.x86.InstRWInfoTable]
|
||||
// ============================================================================
|
||||
|
||||
const NOT_MEM_AMBIGUOUS = MapUtils.arrayToMap([
|
||||
const NOT_MEM_AMBIGUOUS = ArrayUtils.toDict([
|
||||
"call", "movq"
|
||||
]);
|
||||
|
||||
@@ -1974,20 +1967,20 @@ class InstRWInfoTable extends core.Task {
|
||||
run() {
|
||||
const insts = this.ctx.insts;
|
||||
|
||||
const noRmInfo = CxxUtils.struct(
|
||||
const noRmInfo = StringUtils.formatCppStruct(
|
||||
"InstDB::RWInfoRm::kCategory" + "None".padEnd(10),
|
||||
StringUtils.decToHex(0, 2),
|
||||
String(0).padEnd(2),
|
||||
CxxUtils.flags({}),
|
||||
StringUtils.formatCppFlags({}),
|
||||
"0"
|
||||
);
|
||||
|
||||
const noOpInfo = CxxUtils.struct(
|
||||
const noOpInfo = StringUtils.formatCppStruct(
|
||||
"0x0000000000000000u",
|
||||
"0x0000000000000000u",
|
||||
"0xFF",
|
||||
"0",
|
||||
CxxUtils.struct(0),
|
||||
StringUtils.formatCppStruct(0),
|
||||
"OpRWFlags::kNone"
|
||||
);
|
||||
|
||||
@@ -2026,7 +2019,7 @@ class InstRWInfoTable extends core.Task {
|
||||
if (opAcc === "R") flags.Read = true;
|
||||
if (opAcc === "W") flags.Write = true;
|
||||
if (opAcc === "X") flags.RW = true;
|
||||
Lang.merge(flags, op.flags);
|
||||
ObjectUtils.merge(flags, op.flags);
|
||||
|
||||
const rIndex = opAcc === "X" || opAcc === "R" ? op.index : -1;
|
||||
const rWidth = opAcc === "X" || opAcc === "R" ? op.width : -1;
|
||||
@@ -2035,23 +2028,23 @@ class InstRWInfoTable extends core.Task {
|
||||
|
||||
const consecutiveLeadCount = op.clc;
|
||||
|
||||
const opData = CxxUtils.struct(
|
||||
const opData = StringUtils.formatCppStruct(
|
||||
this.byteMaskFromBitRanges([{ start: rIndex, end: rIndex + rWidth - 1 }]) + "u",
|
||||
this.byteMaskFromBitRanges([{ start: wIndex, end: wIndex + wWidth - 1 }]) + "u",
|
||||
StringUtils.decToHex(op.fixed === -1 ? 0xFF : op.fixed, 2),
|
||||
String(consecutiveLeadCount),
|
||||
CxxUtils.struct(0),
|
||||
CxxUtils.flags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone")
|
||||
StringUtils.formatCppStruct(0),
|
||||
StringUtils.formatCppFlags(flags, function(flag) { return "OpRWFlags::k" + flag; }, "OpRWFlags::kNone")
|
||||
);
|
||||
|
||||
rwOpsIndex.push(this.opInfoTable.addIndexed(opData));
|
||||
}
|
||||
|
||||
const rmData = CxxUtils.struct(
|
||||
const rmData = StringUtils.formatCppStruct(
|
||||
"InstDB::RWInfoRm::kCategory" + rmInfo.category.padEnd(10),
|
||||
StringUtils.decToHex(rmInfo.rmIndexes, 2),
|
||||
String(Math.max(rmInfo.memFixed, 0)).padEnd(2),
|
||||
CxxUtils.flags({
|
||||
StringUtils.formatCppFlags({
|
||||
"InstDB::RWInfoRm::kFlagAmbiguous": Boolean(rmInfo.memAmbiguous),
|
||||
"InstDB::RWInfoRm::kFlagMovssMovsd": Boolean(inst.name === "movss" || inst.name === "movsd"),
|
||||
"InstDB::RWInfoRm::kFlagPextrw": Boolean(inst.name === "pextrw"),
|
||||
@@ -2060,10 +2053,10 @@ class InstRWInfoTable extends core.Task {
|
||||
rmInfo.memExtension === "None" ? "0" : "uint32_t(CpuFeatures::X86::k" + rmInfo.memExtension + ")"
|
||||
);
|
||||
|
||||
const rwData = CxxUtils.struct(
|
||||
const rwData = StringUtils.formatCppStruct(
|
||||
"InstDB::RWInfo::kCategory" + rwInfo.category.padEnd(10),
|
||||
String(this.rmInfoTable.addIndexed(rmData)).padEnd(2),
|
||||
CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
|
||||
StringUtils.formatCppStruct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
|
||||
);
|
||||
|
||||
if (i == 0)
|
||||
@@ -2218,12 +2211,12 @@ class InstRWInfoTable extends core.Task {
|
||||
rwOps[j] = d;
|
||||
}
|
||||
else {
|
||||
if (!Lang.deepEqExcept(rwOps[j], d, { "fixed": true, "flags": true }))
|
||||
if (!ObjectUtils.equalsExcept(rwOps[j], d, { "fixed": true, "flags": true }))
|
||||
return null;
|
||||
|
||||
if (rwOps[j].fixed === -1)
|
||||
rwOps[j].fixed = d.fixed;
|
||||
Lang.merge(rwOps[j].flags, d.flags);
|
||||
ObjectUtils.merge(rwOps[j].flags, d.flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2252,7 +2245,7 @@ class InstRWInfoTable extends core.Task {
|
||||
|
||||
var match = 0;
|
||||
for (var j = 0; j < rwOpsArray.length; j++)
|
||||
match |= Lang.deepEq(rwOps, rwOpsArray[j]);
|
||||
match |= ObjectUtils.equals(rwOps, rwOpsArray[j]);
|
||||
|
||||
if (!match)
|
||||
return false;
|
||||
@@ -2309,7 +2302,7 @@ class InstRWInfoTable extends core.Task {
|
||||
}
|
||||
|
||||
rwOpFlagsForInstruction(instName, opIndex) {
|
||||
const toMap = MapUtils.arrayToMap;
|
||||
const toMap = ArrayUtils.toDict;
|
||||
|
||||
// TODO: We should be able to get this information from asmdb.
|
||||
switch (instName + "@" + opIndex) {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
const commons = require("./gencommons.js");
|
||||
const cxx = require("./gencxx.js");
|
||||
const commons = require("./generator-commons.js");
|
||||
const cxx = require("./generator-cxx.js");
|
||||
const asmdb = require("../db");
|
||||
|
||||
exports.asmdb = asmdb;
|
||||
@@ -28,528 +28,11 @@ exports.exp = asmdb.base.exp;
|
||||
const hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
const FATAL = commons.FATAL;
|
||||
const StringUtils = commons.StringUtils;
|
||||
|
||||
// ============================================================================
|
||||
// [Constants]
|
||||
// ============================================================================
|
||||
|
||||
const kIndent = " ";
|
||||
const kJustify = 119;
|
||||
const kAsmJitRoot = "..";
|
||||
|
||||
exports.kIndent = kIndent;
|
||||
exports.kJustify = kJustify;
|
||||
exports.kAsmJitRoot = kAsmJitRoot;
|
||||
|
||||
// ============================================================================
|
||||
// [Lang]
|
||||
// ============================================================================
|
||||
|
||||
function nop(x) { return x; }
|
||||
|
||||
class Lang {
|
||||
static merge(a, b) {
|
||||
if (a === b)
|
||||
return a;
|
||||
|
||||
for (var k in b) {
|
||||
var av = a[k];
|
||||
var bv = b[k];
|
||||
|
||||
if (typeof av === "object" && typeof bv === "object")
|
||||
Lang.merge(av, bv);
|
||||
else
|
||||
a[k] = bv;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static deepEq(a, b) {
|
||||
if (a === b)
|
||||
return true;
|
||||
|
||||
if (typeof a !== typeof b)
|
||||
return false;
|
||||
|
||||
if (typeof a !== "object")
|
||||
return a === b;
|
||||
|
||||
if (Array.isArray(a) || Array.isArray(b)) {
|
||||
if (Array.isArray(a) !== Array.isArray(b))
|
||||
return false;
|
||||
|
||||
const len = a.length;
|
||||
if (b.length !== len)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
if (!Lang.deepEq(a[i], b[i]))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (a === null || b === null)
|
||||
return a === b;
|
||||
|
||||
for (var k in a)
|
||||
if (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k]))
|
||||
return false;
|
||||
|
||||
for (var k in b)
|
||||
if (!hasOwn.call(a, k))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static deepEqExcept(a, b, except) {
|
||||
if (a === b)
|
||||
return true;
|
||||
|
||||
if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b))
|
||||
return Lang.deepEq(a, b);
|
||||
|
||||
for (var k in a)
|
||||
if (!hasOwn.call(except, k) && (!hasOwn.call(b, k) || !Lang.deepEq(a[k], b[k])))
|
||||
return false;
|
||||
|
||||
for (var k in b)
|
||||
if (!hasOwn.call(except, k) && !hasOwn.call(a, k))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.Lang = Lang;
|
||||
|
||||
// ============================================================================
|
||||
// [StringUtils]
|
||||
// ============================================================================
|
||||
|
||||
class StringUtils {
|
||||
static asString(x) { return String(x); }
|
||||
|
||||
static countOf(s, pattern) {
|
||||
if (!pattern)
|
||||
FATAL(`Pattern cannot be empty`);
|
||||
|
||||
var n = 0;
|
||||
var pos = 0;
|
||||
|
||||
while ((pos = s.indexOf(pattern, pos)) >= 0) {
|
||||
n++;
|
||||
pos += pattern.length;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static trimLeft(s) { return s.replace(/^\s+/, ""); }
|
||||
static trimRight(s) { return s.replace(/\s+$/, ""); }
|
||||
|
||||
static upFirst(s) {
|
||||
if (!s) return "";
|
||||
return s[0].toUpperCase() + s.substr(1);
|
||||
}
|
||||
|
||||
static decToHex(n, nPad) {
|
||||
var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
|
||||
while (nPad > hex.length)
|
||||
hex = "0" + hex;
|
||||
return "0x" + hex.toUpperCase();
|
||||
}
|
||||
|
||||
static format(array, indent, showIndex, mapFn) {
|
||||
if (!mapFn)
|
||||
mapFn = StringUtils.asString;
|
||||
|
||||
var s = "";
|
||||
var threshold = 80;
|
||||
|
||||
if (showIndex === -1)
|
||||
s += indent;
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const last = i === array.length - 1;
|
||||
|
||||
if (showIndex !== -1)
|
||||
s += indent;
|
||||
|
||||
s += mapFn(item);
|
||||
if (showIndex > 0) {
|
||||
s += `${last ? " " : ","} // #${i}`;
|
||||
if (typeof array.refCountOf === "function")
|
||||
s += ` [ref=${array.refCountOf(item)}x]`;
|
||||
}
|
||||
else if (!last) {
|
||||
s += ",";
|
||||
}
|
||||
|
||||
if (showIndex === -1) {
|
||||
if (s.length >= threshold - 1 && !last) {
|
||||
s += "\n" + indent;
|
||||
threshold += 80;
|
||||
}
|
||||
else {
|
||||
if (!last) s += " ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!last) s += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static makeCxxArray(array, code, indent) {
|
||||
if (!indent) indent = kIndent;
|
||||
return `${code} = {\n${indent}` + array.join(`,\n${indent}`) + `\n};\n`;
|
||||
}
|
||||
|
||||
static makeCxxArrayWithComment(array, code, indent) {
|
||||
if (!indent) indent = kIndent;
|
||||
var s = "";
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
const last = i === array.length - 1;
|
||||
s += indent + array[i].data +
|
||||
(last ? " // " : ", // ") + (array[i].refs ? "#" + String(i) : "").padEnd(5) + array[i].comment + "\n";
|
||||
}
|
||||
return `${code} = {\n${s}};\n`;
|
||||
}
|
||||
|
||||
static disclaimer(s) {
|
||||
return "// ------------------- Automatically generated, do not edit -------------------\n" +
|
||||
s +
|
||||
"// ----------------------------------------------------------------------------\n";
|
||||
}
|
||||
|
||||
static indent(s, indentation) {
|
||||
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");
|
||||
}
|
||||
|
||||
static extract(s, start, end) {
|
||||
var iStart = s.indexOf(start);
|
||||
var iEnd = s.indexOf(end);
|
||||
|
||||
if (iStart === -1)
|
||||
FATAL(`StringUtils.extract(): Couldn't locate start mark '${start}'`);
|
||||
|
||||
if (iEnd === -1)
|
||||
FATAL(`StringUtils.extract(): Couldn't locate end mark '${end}'`);
|
||||
|
||||
return s.substring(iStart + start.length, iEnd).trim();
|
||||
}
|
||||
|
||||
static inject(s, start, end, code) {
|
||||
var iStart = s.indexOf(start);
|
||||
var iEnd = s.indexOf(end);
|
||||
|
||||
if (iStart === -1)
|
||||
FATAL(`StringUtils.inject(): Couldn't locate start mark '${start}'`);
|
||||
|
||||
if (iEnd === -1)
|
||||
FATAL(`StringUtils.inject(): Couldn't locate end mark '${end}'`);
|
||||
|
||||
var nIndent = 0;
|
||||
while (iStart > 0 && s[iStart-1] === " ") {
|
||||
iStart--;
|
||||
nIndent++;
|
||||
}
|
||||
|
||||
if (nIndent) {
|
||||
const indentation = " ".repeat(nIndent);
|
||||
code = StringUtils.indent(code, indentation) + indentation;
|
||||
}
|
||||
|
||||
return s.substr(0, iStart + start.length + nIndent) + code + s.substr(iEnd);
|
||||
}
|
||||
|
||||
static makePriorityCompare(priorityArray) {
|
||||
const map = Object.create(null);
|
||||
priorityArray.forEach((str, index) => { map[str] = index; });
|
||||
|
||||
return function(a, b) {
|
||||
const ax = hasOwn.call(map, a) ? map[a] : Infinity;
|
||||
const bx = hasOwn.call(map, b) ? map[b] : Infinity;
|
||||
return ax != bx ? ax - bx : a < b ? -1 : a > b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.StringUtils = StringUtils;
|
||||
|
||||
// ============================================================================
|
||||
// [ArrayUtils]
|
||||
// ============================================================================
|
||||
|
||||
class ArrayUtils {
|
||||
static min(arr, fn) {
|
||||
if (!arr.length)
|
||||
return null;
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
var v = fn(arr[0]);
|
||||
for (var i = 1; i < arr.length; i++)
|
||||
v = Math.min(v, fn(arr[i]));
|
||||
return v;
|
||||
}
|
||||
|
||||
static max(arr, fn) {
|
||||
if (!arr.length)
|
||||
return null;
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
var v = fn(arr[0]);
|
||||
for (var i = 1; i < arr.length; i++)
|
||||
v = Math.max(v, fn(arr[i]));
|
||||
return v;
|
||||
}
|
||||
|
||||
static sorted(obj, cmp) {
|
||||
const out = Array.isArray(obj) ? obj.slice() : Object.getOwnPropertyNames(obj);
|
||||
out.sort(cmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
static deepIndexOf(arr, what) {
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
if (Lang.deepEq(arr[i], what))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
exports.ArrayUtils = ArrayUtils;
|
||||
|
||||
// ============================================================================
|
||||
// [MapUtils]
|
||||
// ============================================================================
|
||||
|
||||
class MapUtils {
|
||||
static clone(map) {
|
||||
return Object.assign(Object.create(null), map);
|
||||
}
|
||||
|
||||
static arrayToMap(arr, value) {
|
||||
if (value === undefined)
|
||||
value = true;
|
||||
|
||||
const out = Object.create(null);
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
out[arr[i]] = value;
|
||||
return out;
|
||||
}
|
||||
|
||||
static equals(a, b) {
|
||||
for (var k in a) if (!hasOwn.call(b, k)) return false;
|
||||
for (var k in b) if (!hasOwn.call(a, k)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static firstOf(map, flags) {
|
||||
for (var k in flags)
|
||||
if (hasOwn.call(map, k))
|
||||
return k;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static anyOf(map, flags) {
|
||||
for (var k in flags)
|
||||
if (hasOwn.call(map, k))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static add(a, b) {
|
||||
for (var k in b)
|
||||
a[k] = b[k];
|
||||
return a;
|
||||
}
|
||||
|
||||
static and(a, b) {
|
||||
const out = Object.create(null);
|
||||
for (var k in a)
|
||||
if (hasOwn.call(b, k))
|
||||
out[k] = true;
|
||||
return out;
|
||||
}
|
||||
|
||||
static xor(a, b) {
|
||||
const out = Object.create(null);
|
||||
for (var k in a) if (!hasOwn.call(b, k)) out[k] = true;
|
||||
for (var k in b) if (!hasOwn.call(a, k)) out[k] = true;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
exports.MapUtils = MapUtils;
|
||||
|
||||
// ============================================================================
|
||||
// [CxxUtils]
|
||||
// ============================================================================
|
||||
|
||||
class CxxUtils {
|
||||
static flags(obj, fn, none) {
|
||||
if (none == null)
|
||||
none = "0";
|
||||
|
||||
if (!fn)
|
||||
fn = nop;
|
||||
|
||||
let out = "";
|
||||
for (let k in obj) {
|
||||
if (obj[k])
|
||||
out += (out ? " | " : "") + fn(k);
|
||||
}
|
||||
return out ? out : none;
|
||||
}
|
||||
|
||||
static struct(...args) {
|
||||
return "{ " + args.join(", ") + " }";
|
||||
}
|
||||
};
|
||||
exports.CxxUtils = CxxUtils;
|
||||
|
||||
// ============================================================================
|
||||
// [IndexedString]
|
||||
// ============================================================================
|
||||
|
||||
// IndexedString is mostly used to merge all instruction names into a single
|
||||
// string with external index. It's designed mostly for generating C++ tables.
|
||||
//
|
||||
// Consider the following cases in C++:
|
||||
//
|
||||
// a) static const char* const* instNames = { "add", "mov", "vpunpcklbw" };
|
||||
//
|
||||
// b) static const char instNames[] = { "add\0" "mov\0" "vpunpcklbw\0" };
|
||||
// static const uint16_t instNameIndex[] = { 0, 4, 8 };
|
||||
//
|
||||
// The latter (b) has an advantage that it doesn't have to be relocated by the
|
||||
// linker, which saves a lot of space in the resulting binary and a lot of CPU
|
||||
// cycles (and memory) when the linker loads it. AsmJit supports thousands of
|
||||
// instructions so each optimization like this makes it smaller and faster to
|
||||
// load.
|
||||
class IndexedString {
|
||||
constructor() {
|
||||
this.map = Object.create(null);
|
||||
this.array = [];
|
||||
this.size = -1;
|
||||
}
|
||||
|
||||
add(s) {
|
||||
this.map[s] = -1;
|
||||
}
|
||||
|
||||
index() {
|
||||
const map = this.map;
|
||||
const array = this.array;
|
||||
const partialMap = Object.create(null);
|
||||
|
||||
var k, kp;
|
||||
var i, len;
|
||||
|
||||
// Create a map that will contain all keys and partial keys.
|
||||
for (k in map) {
|
||||
if (!k) {
|
||||
partialMap[k] = k;
|
||||
}
|
||||
else {
|
||||
for (i = 0, len = k.length; i < len; i++) {
|
||||
kp = k.substr(i);
|
||||
if (!hasOwn.call(partialMap, kp) || partialMap[kp].length < len)
|
||||
partialMap[kp] = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array that will only contain keys that are needed.
|
||||
for (k in map)
|
||||
if (partialMap[k] === k)
|
||||
array.push(k);
|
||||
array.sort();
|
||||
|
||||
// Create valid offsets to the `array`.
|
||||
var offMap = Object.create(null);
|
||||
var offset = 0;
|
||||
|
||||
for (i = 0, len = array.length; i < len; i++) {
|
||||
k = array[i];
|
||||
|
||||
offMap[k] = offset;
|
||||
offset += k.length + 1;
|
||||
}
|
||||
this.size = offset;
|
||||
|
||||
// Assign valid offsets to `map`.
|
||||
for (kp in map) {
|
||||
k = partialMap[kp];
|
||||
map[kp] = offMap[k] + k.length - kp.length;
|
||||
}
|
||||
}
|
||||
|
||||
format(indent, justify) {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.format(): not indexed yet, call index()`);
|
||||
|
||||
const array = this.array;
|
||||
if (!justify) justify = 0;
|
||||
|
||||
var i;
|
||||
var s = "";
|
||||
var line = "";
|
||||
|
||||
for (i = 0; i < array.length; i++) {
|
||||
const item = "\"" + array[i] + ((i !== array.length - 1) ? "\\0\"" : "\";");
|
||||
const newl = line + (line ? " " : indent) + item;
|
||||
|
||||
if (newl.length <= justify) {
|
||||
line = newl;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
s += line + "\n";
|
||||
line = indent + item;
|
||||
}
|
||||
}
|
||||
|
||||
return s + line;
|
||||
}
|
||||
|
||||
getSize() {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.getSize(): Not indexed yet, call index()`);
|
||||
return this.size;
|
||||
}
|
||||
|
||||
getIndex(k) {
|
||||
if (this.size === -1)
|
||||
FATAL(`IndexedString.getIndex(): Not indexed yet, call index()`);
|
||||
|
||||
if (!hasOwn.call(this.map, k))
|
||||
FATAL(`IndexedString.getIndex(): Key '${k}' not found.`);
|
||||
|
||||
return this.map[k];
|
||||
}
|
||||
}
|
||||
exports.IndexedString = IndexedString;
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// [InstructionNameData]
|
||||
// ============================================================================
|
||||
@@ -751,51 +234,6 @@ class InstructionNameData {
|
||||
}
|
||||
exports.InstructionNameData = InstructionNameData;
|
||||
|
||||
// ============================================================================
|
||||
// [IndexedArray]
|
||||
// ============================================================================
|
||||
|
||||
// IndexedArray is an Array replacement that allows to index each item inserted
|
||||
// to it. Its main purpose is to avoid data duplication, if an item passed to
|
||||
// `addIndexed()` is already within the Array then it's not inserted and the
|
||||
// existing index is returned instead.
|
||||
function IndexedArray_keyOf(item) {
|
||||
return typeof item === "string" ? item : JSON.stringify(item);
|
||||
}
|
||||
|
||||
class IndexedArray extends Array {
|
||||
constructor() {
|
||||
super();
|
||||
this._index = Object.create(null);
|
||||
}
|
||||
|
||||
refCountOf(item) {
|
||||
const key = IndexedArray_keyOf(item);
|
||||
const idx = this._index[key];
|
||||
|
||||
return idx !== undefined ? idx.refCount : 0;
|
||||
}
|
||||
|
||||
addIndexed(item) {
|
||||
const key = IndexedArray_keyOf(item);
|
||||
var idx = this._index[key];
|
||||
|
||||
if (idx !== undefined) {
|
||||
idx.refCount++;
|
||||
return idx.data;
|
||||
}
|
||||
|
||||
idx = this.length;
|
||||
this._index[key] = {
|
||||
data: idx,
|
||||
refCount: 1
|
||||
};
|
||||
this.push(item);
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
exports.IndexedArray = IndexedArray;
|
||||
|
||||
// ============================================================================
|
||||
// [Task]
|
||||
// ============================================================================
|
||||
@@ -823,29 +261,12 @@ exports.Task = Task;
|
||||
// [TableGen]
|
||||
// ============================================================================
|
||||
|
||||
// Main context used to load, generate, and store instruction tables. The idea
|
||||
// is to be extensible, so it stores 'Task's to be executed with minimal deps
|
||||
// management.
|
||||
class TableGen {
|
||||
constructor(arch) {
|
||||
this.arch = arch;
|
||||
class Injector {
|
||||
constructor() {
|
||||
this.files = Object.create(null);
|
||||
this.tableSizes = Object.create(null);
|
||||
|
||||
this.tasks = [];
|
||||
this.taskMap = Object.create(null);
|
||||
|
||||
this.insts = [];
|
||||
this.instMap = Object.create(null);
|
||||
|
||||
this.aliases = [];
|
||||
this.aliasMem = Object.create(null);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [File Management]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
load(fileList) {
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
const file = fileList[i];
|
||||
@@ -905,6 +326,42 @@ class TableGen {
|
||||
return this;
|
||||
}
|
||||
|
||||
dumpTableSizes() {
|
||||
const sizes = this.tableSizes;
|
||||
|
||||
var pad = 26;
|
||||
var total = 0;
|
||||
|
||||
for (var name in sizes) {
|
||||
const size = sizes[name];
|
||||
total += size;
|
||||
console.log(("Size of " + name).padEnd(pad) + ": " + size);
|
||||
}
|
||||
|
||||
console.log("Size of all tables".padEnd(pad) + ": " + total);
|
||||
}
|
||||
}
|
||||
exports.Injector = Injector;
|
||||
|
||||
// Main context used to load, generate, and store instruction tables. The idea
|
||||
// is to be extensible, so it stores 'Task's to be executed with minimal deps
|
||||
// management.
|
||||
class TableGen extends Injector{
|
||||
constructor(arch) {
|
||||
super();
|
||||
|
||||
this.arch = arch;
|
||||
|
||||
this.tasks = [];
|
||||
this.taskMap = Object.create(null);
|
||||
|
||||
this.insts = [];
|
||||
this.instMap = Object.create(null);
|
||||
|
||||
this.aliases = [];
|
||||
this.aliasMem = Object.create(null);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Task Management]
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -989,25 +446,6 @@ class TableGen {
|
||||
this.onAfterRun();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Other]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
dumpTableSizes() {
|
||||
const sizes = this.tableSizes;
|
||||
|
||||
var pad = 26;
|
||||
var total = 0;
|
||||
|
||||
for (var name in sizes) {
|
||||
const size = sizes[name];
|
||||
total += size;
|
||||
console.log(("Size of " + name).padEnd(pad) + ": " + size);
|
||||
}
|
||||
|
||||
console.log("Size of all tables".padEnd(pad) + ": " + total);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [Hooks]
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -1056,59 +494,75 @@ exports.IdEnum = IdEnum;
|
||||
// [NameTable]
|
||||
// ============================================================================
|
||||
|
||||
class Output {
|
||||
constructor() {
|
||||
this.content = Object.create(null);
|
||||
this.tableSize = Object.create(null);
|
||||
}
|
||||
|
||||
add(id, content, tableSize) {
|
||||
this.content[id] = content;
|
||||
this.tableSize[id] = typeof tableSize === "number" ? tableSize : 0;
|
||||
}
|
||||
};
|
||||
exports.Output = Output;
|
||||
|
||||
function generateNameData(out, instructions) {
|
||||
const none = "Inst::kIdNone";
|
||||
|
||||
const instFirst = new Array(26);
|
||||
const instLast = new Array(26);
|
||||
const instNameData = new InstructionNameData();
|
||||
|
||||
for (let i = 0; i < instructions.length; i++)
|
||||
instNameData.add(instructions[i].displayName);
|
||||
instNameData.index();
|
||||
|
||||
for (let i = 0; i < instructions.length; i++) {
|
||||
const inst = instructions[i];
|
||||
const displayName = inst.displayName;
|
||||
const alphaIndex = displayName.charCodeAt(0) - 'a'.charCodeAt(0);
|
||||
|
||||
if (alphaIndex < 0 || alphaIndex >= 26)
|
||||
FATAL(`generateNameData(): Invalid lookup character '${displayName[0]}' of '${displayName}'`);
|
||||
|
||||
if (instFirst[alphaIndex] === undefined)
|
||||
instFirst[alphaIndex] = `Inst::kId${inst.enum}`;
|
||||
instLast[alphaIndex] = `Inst::kId${inst.enum}`;
|
||||
}
|
||||
|
||||
var s = "";
|
||||
s += `const InstNameIndex InstDB::instNameIndex = {{\n`;
|
||||
for (var i = 0; i < instFirst.length; i++) {
|
||||
const firstId = instFirst[i] || none;
|
||||
const lastId = instLast[i] || none;
|
||||
|
||||
s += ` { ${String(firstId).padEnd(22)}, ${String(lastId).padEnd(22)} + 1 }`;
|
||||
if (i !== 26 - 1)
|
||||
s += `,`;
|
||||
s += `\n`;
|
||||
}
|
||||
s += `}, uint16_t(${instNameData.maxNameLength})};\n`;
|
||||
s += `\n`;
|
||||
s += instNameData.formatStringTable("InstDB::_instNameStringTable");
|
||||
s += `\n`;
|
||||
s += instNameData.formatIndexTable("InstDB::_instNameIndexTable");
|
||||
|
||||
const dataSize = instNameData.getSize() + 26 * 4;
|
||||
out.add("NameData", StringUtils.disclaimer(s), dataSize);
|
||||
return out;
|
||||
}
|
||||
exports.generateNameData = generateNameData;
|
||||
|
||||
class NameTable extends Task {
|
||||
constructor(name, deps) {
|
||||
super(name || "NameTable", deps);
|
||||
}
|
||||
|
||||
run() {
|
||||
const none = "Inst::kIdNone";
|
||||
const insts = this.ctx.insts;
|
||||
|
||||
const instFirst = new Array(26);
|
||||
const instLast = new Array(26);
|
||||
|
||||
const instNameData = new InstructionNameData();
|
||||
|
||||
for (let i = 0; i < insts.length; i++)
|
||||
instNameData.add(insts[i].displayName);
|
||||
instNameData.index();
|
||||
|
||||
for (let i = 0; i < insts.length; i++) {
|
||||
const inst = insts[i];
|
||||
const name = inst.displayName;
|
||||
const index = name.charCodeAt(0) - 'a'.charCodeAt(0);
|
||||
|
||||
if (index < 0 || index >= 26)
|
||||
FATAL(`TableGen.generateNameData(): Invalid lookup character '${name[0]}' of '${name}'`);
|
||||
|
||||
if (instFirst[index] === undefined)
|
||||
instFirst[index] = `Inst::kId${inst.enum}`;
|
||||
instLast[index] = `Inst::kId${inst.enum}`;
|
||||
}
|
||||
|
||||
var s = "";
|
||||
s += instNameData.formatIndexTable("InstDB::_instNameIndexTable");
|
||||
s += `\n`;
|
||||
s += instNameData.formatStringTable("InstDB::_instNameStringTable");
|
||||
s += `\n`;
|
||||
|
||||
s += `const InstDB::InstNameIndex InstDB::instNameIndex[26] = {\n`;
|
||||
for (var i = 0; i < instFirst.length; i++) {
|
||||
const firstId = instFirst[i] || none;
|
||||
const lastId = instLast[i] || none;
|
||||
|
||||
s += ` { ${String(firstId).padEnd(22)}, ${String(lastId).padEnd(22)} + 1 }`;
|
||||
if (i !== 26 - 1)
|
||||
s += `,`;
|
||||
s += `\n`;
|
||||
}
|
||||
s += `};\n`;
|
||||
|
||||
this.ctx.inject("NameLimits",
|
||||
StringUtils.disclaimer(`enum : uint32_t { kMaxNameSize = ${instNameData.maxNameLength} };\n`));
|
||||
|
||||
return this.ctx.inject("NameData", StringUtils.disclaimer(s), instNameData.getSize() + 26 * 4);
|
||||
const output = new Output();
|
||||
generateNameData(output, this.ctx.insts);
|
||||
this.ctx.inject("NameData", output.content["NameData"], output.tableSize["NameData"]);
|
||||
}
|
||||
}
|
||||
exports.NameTable = NameTable;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
node ./tablegen-a32.js $@
|
||||
node ./tablegen-a64.js $@
|
||||
node ./tablegen-x86.js $@
|
||||
|
||||
Reference in New Issue
Block a user