[abi] Added support for 32-bit ARM (WIP)

This commit is contained in:
kobalicek
2025-11-29 09:13:58 +01:00
parent 12f9ca3b32
commit 594cb9e071
35 changed files with 21406 additions and 12 deletions

View File

@@ -70,6 +70,7 @@ option(ASMJIT_NO_CUSTOM_FLAGS "Disable extra compilation flags added by AsmJit
option(ASMJIT_NO_ABI_NAMESPACE "Disable the use of inline ABI namespace {asmjit::v...}" OFF)
option(ASMJIT_NO_SHM_OPEN "Disable the use of shm_open() (some platforms have better options)" OFF)
option(ASMJIT_NO_X86 "Disable X86/X64 backend" OFF)
option(ASMJIT_NO_AARCH32 "Disable AArch32 backend" OFF)
option(ASMJIT_NO_AARCH64 "Disable AArch64 backend" OFF)
option(ASMJIT_NO_FOREIGN "Disable all foreign backends (enables only a backend that matches the target)" OFF)
option(ASMJIT_NO_JIT "Disable VirtMem, JitAllocator, and JitRuntime at build time" OFF)
@@ -219,12 +220,29 @@ set(ASMJIT_SRC
asmjit/support/support.h
asmjit/support/support_p.h
asmjit/a32.h
asmjit/a64.h
asmjit/arm.h
asmjit/arm/armformatter.cpp
asmjit/arm/armformatter_p.h
asmjit/arm/armglobals.h
asmjit/arm/armutils.h
asmjit/arm/a32archtraits_p.h
asmjit/arm/a32assembler.cpp
asmjit/arm/a32assembler.h
asmjit/arm/a32builder.cpp
asmjit/arm/a32builder.h
asmjit/arm/a32emithelper.cpp
asmjit/arm/a32emithelper_p.h
asmjit/arm/a32emitter.h
asmjit/arm/a32formatter.cpp
asmjit/arm/a32formatter_p.h
asmjit/arm/a32globals.h
asmjit/arm/a32instapi.cpp
asmjit/arm/a32instapi_p.h
asmjit/arm/a32instdb.cpp
asmjit/arm/a32instdb_p.h
asmjit/arm/a32operand.h
asmjit/arm/a64archtraits_p.h
asmjit/arm/a64assembler.cpp
asmjit/arm/a64assembler.h
@@ -504,6 +522,7 @@ if (ASMJIT_NO_SHM_OPEN)
endif()
foreach(build_option ASMJIT_NO_X86
ASMJIT_NO_AARCH32
ASMJIT_NO_AARCH64
ASMJIT_NO_FOREIGN
ASMJIT_NO_ABI_NAMESPACE
@@ -613,6 +632,7 @@ else()
asmjit_add_target(asmjit_test_assembler TEST
SOURCES asmjit-testing/tests/asmjit_test_assembler.cpp
asmjit-testing/tests/asmjit_test_assembler.h
asmjit-testing/tests/asmjit_test_assembler_a32.cpp
asmjit-testing/tests/asmjit_test_assembler_a64.cpp
asmjit-testing/tests/asmjit_test_assembler_x64.cpp
asmjit-testing/tests/asmjit_test_assembler_x86.cpp
@@ -689,6 +709,7 @@ else()
asmjit_add_target(asmjit_bench_codegen EXECUTABLE
SOURCES asmjit-testing/bench/asmjit_bench_codegen.cpp
asmjit-testing/bench/asmjit_bench_codegen_a32.cpp
asmjit-testing/bench/asmjit_bench_codegen_a64.cpp
asmjit-testing/bench/asmjit_bench_codegen_x86.cpp
SOURCES asmjit-testing/bench/asmjit_bench_codegen.h

View File

@@ -28,6 +28,10 @@ static void print_app_info() noexcept {
void benchmark_x86_emitters(uint32_t num_iterations, bool test_x86, bool test_x64) noexcept;
#endif
#if !defined(ASMJIT_NO_AARCH32)
void benchmark_aarch32_emitters(uint32_t num_iterations);
#endif
#if !defined(ASMJIT_NO_AARCH64)
void benchmark_aarch64_emitters(uint32_t num_iterations);
#endif
@@ -49,6 +53,9 @@ 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_NO_AARCH32)
printf(" --arch=aarch32 32-bit ARM architecture (AArch32)\n");
#endif
#if !defined(ASMJIT_NO_AARCH64)
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
#endif
@@ -71,6 +78,14 @@ int main(int argc, char* argv[]) {
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
bool test_aarch32 = strcmp(arch, "all") == 0 || strcmp(arch, "aarch32") == 0;
if (test_aarch32) {
benchmark_aarch32_emitters(num_iterations);
}
#endif
#if !defined(ASMJIT_NO_AARCH64)
bool test_aarch64 = strcmp(arch, "all") == 0 || strcmp(arch, "aarch64") == 0;

View File

@@ -0,0 +1,23 @@
// This file is part of AsmJit project <https://asmjit.com>
//
// See <asmjit/core.h> or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#include <asmjit/core.h>
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/a32.h>
#include <limits>
#include <stdio.h>
#include <string.h>
#include <asmjit-testing/bench/asmjit_bench_codegen.h>
using namespace asmjit;
void benchmark_aarch32_emitters(uint32_t num_iterations) {
Support::maybe_unused(num_iterations);
}
#endif // !ASMJIT_NO_AARCH32

View File

@@ -20,6 +20,10 @@ bool test_x86_assembler(const TestSettings& settings) noexcept;
bool test_x64_assembler(const TestSettings& settings) noexcept;
#endif
#if !defined(ASMJIT_NO_AARCH32)
bool test_aarch32_assembler(const TestSettings& settings) noexcept;
#endif
#if !defined(ASMJIT_NO_AARCH64)
bool test_aarch64_assembler(const TestSettings& settings) noexcept;
#endif
@@ -47,6 +51,9 @@ static void print_app_usage(const TestSettings& settings) noexcept {
printf(" --arch=x86 32-bit X86 architecture (X86)\n");
printf(" --arch=x64 64-bit X86 architecture (X86_64)\n");
#endif
#if !defined(ASMJIT_NO_AARCH32)
printf(" --arch=aarch32 32-bit ARM architecture (AArch32)\n");
#endif
#if !defined(ASMJIT_NO_AARCH64)
printf(" --arch=aarch64 64-bit ARM architecture (AArch64)\n");
#endif
@@ -68,34 +75,52 @@ int main(int argc, char* argv[]) {
}
const char* arch = cmd_line.value_of("--arch", "all");
bool x86_failed = false;
bool x64_failed = false;
bool aarch32_failed = false;
bool aarch64_failed = false;
#if !defined(ASMJIT_NO_X86)
if ((strcmp(arch, "all") == 0 || strcmp(arch, "x86") == 0))
if ((strcmp(arch, "all") == 0 || strcmp(arch, "x86") == 0)) {
x86_failed = !test_x86_assembler(settings);
}
if ((strcmp(arch, "all") == 0 || strcmp(arch, "x64") == 0))
if ((strcmp(arch, "all") == 0 || strcmp(arch, "x64") == 0)) {
x64_failed = !test_x64_assembler(settings);
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if ((strcmp(arch, "all") == 0 || strcmp(arch, "aarch32") == 0)) {
aarch32_failed = !test_aarch32_assembler(settings);
}
#endif
#if !defined(ASMJIT_NO_AARCH64)
if ((strcmp(arch, "all") == 0 || strcmp(arch, "aarch64") == 0))
if ((strcmp(arch, "all") == 0 || strcmp(arch, "aarch64") == 0)) {
aarch64_failed = !test_aarch64_assembler(settings);
}
#endif
bool failed = x86_failed || x64_failed || aarch64_failed;
bool failed = x86_failed || x64_failed || aarch32_failed || aarch64_failed;
if (failed) {
if (x86_failed)
if (x86_failed) {
printf("** X86 test suite failed **\n");
}
if (x64_failed)
if (x64_failed) {
printf("** X64 test suite failed **\n");
}
if (aarch64_failed)
if (aarch32_failed) {
printf("** AArch32 test suite failed **\n");
}
if (aarch64_failed) {
printf("** AArch64 test suite failed **\n");
}
printf("** FAILURE **\n");
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,638 @@
// 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 <asmjit/core.h>
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/a32.h>
#include <asmjit-testing/commons/asmjit_test_perf.h.
#include <limits>
#include <stdio.h>
#include <string.h>
using namespace asmjit;
// Generates a long sequence of GP instructions.
template<typename Emitter>
static void generateGpSequenceInternal(
Emitter& cc,
const a32::Gp& a, const a32::Gp& b, const a32::Gp& c, const a32::Gp& d) {
using namespace asmjit::a32;
cc.mov(a, 0);
cc.mov(b, 1);
cc.mov(c, 2);
cc.mov(d, 3);
cc.adc(a, b, c, lsl(d));
cc.adc(a, b, c, lsr(d));
cc.adc(a, b, c, asr(d));
cc.adc(a, b, c, ror(d));
cc.adc(a, b, c, lsl(8));
cc.adc(a, b, c, lsr(8));
cc.adc(a, b, c, asr(8));
cc.adc(a, b, c, ror(8));
cc.adc(a, b, 0xFF);
cc.adc(a, b, 0xFF00);
cc.adc(a, b, 0xFF000000);
cc.adc(a, b, 0xF000000F);
cc.adcs(a, b, c, lsl(d));
cc.adcs(a, b, c, lsr(d));
cc.adcs(a, b, c, asr(d));
cc.adcs(a, b, c, ror(d));
cc.adcs(a, b, c, lsl(8));
cc.adcs(a, b, c, lsr(8));
cc.adcs(a, b, c, asr(8));
cc.adcs(a, b, c, ror(8));
cc.adcs(a, b, 0xFF);
cc.adcs(a, b, 0xFF00);
cc.adcs(a, b, 0xFF000000);
cc.adcs(a, b, 0xF000000F);
cc.add(a, b, c, lsl(d));
cc.add(a, b, c, lsr(d));
cc.add(a, b, c, asr(d));
cc.add(a, b, c, ror(d));
cc.add(a, b, c, lsl(8));
cc.add(a, b, c, lsr(8));
cc.add(a, b, c, asr(8));
cc.add(a, b, c, ror(8));
cc.add(a, b, 0xFF);
cc.add(a, b, 0xFF00);
cc.add(a, b, 0xFF000000);
cc.add(a, b, 0xF000000F);
cc.adds(a, b, c, lsl(d));
cc.adds(a, b, c, lsr(d));
cc.adds(a, b, c, asr(d));
cc.adds(a, b, c, ror(d));
cc.adds(a, b, c, lsl(8));
cc.adds(a, b, c, lsr(8));
cc.adds(a, b, c, asr(8));
cc.adds(a, b, c, ror(8));
cc.adds(a, b, 0xFF);
cc.adds(a, b, 0xFF00);
cc.adds(a, b, 0xFF000000);
cc.adds(a, b, 0xF000000F);
cc.and_(a, b, c, lsl(d));
cc.and_(a, b, c, lsr(d));
cc.and_(a, b, c, asr(d));
cc.and_(a, b, c, ror(d));
cc.and_(a, b, c, lsl(8));
cc.and_(a, b, c, lsr(8));
cc.and_(a, b, c, asr(8));
cc.and_(a, b, c, ror(8));
cc.and_(a, b, 0xFF);
cc.and_(a, b, 0xFF00);
cc.and_(a, b, 0xFF000000);
cc.and_(a, b, 0xF000000F);
cc.ands(a, b, c, lsl(d));
cc.ands(a, b, c, lsr(d));
cc.ands(a, b, c, asr(d));
cc.ands(a, b, c, ror(d));
cc.ands(a, b, c, lsl(8));
cc.ands(a, b, c, lsr(8));
cc.ands(a, b, c, asr(8));
cc.ands(a, b, c, ror(8));
cc.ands(a, b, 0xFF);
cc.ands(a, b, 0xFF00);
cc.ands(a, b, 0xFF000000);
cc.ands(a, b, 0xF000000F);
cc.asr(a, b, c);
cc.asr(a, b, 3);
cc.asrs(a, b, c);
cc.asrs(a, b, 3);
cc.bfc(a, 3, 5);
cc.bfi(a, b, 3, 5);
cc.bic(a, b, c, lsl(d));
cc.bic(a, b, c, lsr(d));
cc.bic(a, b, c, asr(d));
cc.bic(a, b, c, ror(d));
cc.bic(a, b, c, lsl(8));
cc.bic(a, b, c, lsr(8));
cc.bic(a, b, c, asr(8));
cc.bic(a, b, c, ror(8));
cc.bic(a, b, 0xFF);
cc.bic(a, b, 0xFF00);
cc.bic(a, b, 0xFF000000);
cc.bic(a, b, 0xF000000F);
cc.bics(a, b, c, lsl(d));
cc.bics(a, b, c, lsr(d));
cc.bics(a, b, c, asr(d));
cc.bics(a, b, c, ror(d));
cc.bics(a, b, c, lsl(8));
cc.bics(a, b, c, lsr(8));
cc.bics(a, b, c, asr(8));
cc.bics(a, b, c, ror(8));
cc.bics(a, b, 0xFF);
cc.bics(a, b, 0xFF00);
cc.bics(a, b, 0xFF000000);
cc.bics(a, b, 0xF000000F);
cc.clz(a, b);
cc.cmn(a, b, lsl(c));
cc.cmn(a, b, lsr(c));
cc.cmn(a, b, asr(c));
cc.cmn(a, b, ror(c));
cc.cmn(a, b, lsl(8));
cc.cmn(a, b, lsr(8));
cc.cmn(a, b, asr(8));
cc.cmn(a, b, ror(8));
cc.cmn(a, 0xFF);
cc.cmn(a, 0xFF00);
cc.cmn(a, 0xFF000000);
cc.cmn(a, 0xF000000F);
cc.cmp(a, b, lsl(c));
cc.cmp(a, b, lsr(c));
cc.cmp(a, b, asr(c));
cc.cmp(a, b, ror(c));
cc.cmp(a, b, lsl(8));
cc.cmp(a, b, lsr(8));
cc.cmp(a, b, asr(8));
cc.cmp(a, b, ror(8));
cc.cmp(a, 0xFF);
cc.cmp(a, 0xFF00);
cc.cmp(a, 0xFF000000);
cc.cmp(a, 0xF000000F);
cc.crc32b(a, b, c);
cc.crc32cb(a, b, c);
cc.crc32ch(a, b, c);
cc.crc32cw(a, b, c);
cc.crc32h(a, b, c);
cc.crc32w(a, b, c);
cc.eor(a, b, c, lsl(d));
cc.eor(a, b, c, lsr(d));
cc.eor(a, b, c, asr(d));
cc.eor(a, b, c, ror(d));
cc.eor(a, b, c, lsl(8));
cc.eor(a, b, c, lsr(8));
cc.eor(a, b, c, asr(8));
cc.eor(a, b, c, ror(8));
cc.eor(a, b, 0xFF);
cc.eor(a, b, 0xFF00);
cc.eor(a, b, 0xFF000000);
cc.eor(a, b, 0xF000000F);
cc.eors(a, b, c, lsl(d));
cc.eors(a, b, c, lsr(d));
cc.eors(a, b, c, asr(d));
cc.eors(a, b, c, ror(d));
cc.eors(a, b, c, lsl(8));
cc.eors(a, b, c, lsr(8));
cc.eors(a, b, c, asr(8));
cc.eors(a, b, c, ror(8));
cc.eors(a, b, 0xFF);
cc.eors(a, b, 0xFF00);
cc.eors(a, b, 0xFF000000);
cc.eors(a, b, 0xF000000F);
cc.ldr(a, ptr(b, c));
cc.ldr(a, ptr_pre(b, c));
cc.ldr(a, ptr_post(b, c));
cc.ldr(a, ptr(b, 4));
cc.ldr(a, ptr_pre(b, 4));
cc.ldr(a, ptr_post(b, 4));
cc.ldrb(a, ptr(b, c));
cc.ldrb(a, ptr_pre(b, c));
cc.ldrb(a, ptr_post(b, c));
cc.ldrb(a, ptr(b, 4));
cc.ldrb(a, ptr_pre(b, 4));
cc.ldrb(a, ptr_post(b, 4));
cc.ldrbt(a, ptr_post(b, c));
cc.ldrbt(a, ptr_post(b, 4));
cc.ldrh(a, ptr(b, c));
cc.ldrh(a, ptr_pre(b, c));
cc.ldrh(a, ptr_post(b, c));
cc.ldrh(a, ptr(b, 4));
cc.ldrh(a, ptr_pre(b, 4));
cc.ldrh(a, ptr_post(b, 4));
cc.ldrht(a, ptr_post(b, c));
cc.ldrht(a, ptr_post(b, 4));
cc.ldrsb(a, ptr(b, c));
cc.ldrsb(a, ptr_pre(b, c));
cc.ldrsb(a, ptr_post(b, c));
cc.ldrsb(a, ptr(b, 4));
cc.ldrsb(a, ptr_pre(b, 4));
cc.ldrsb(a, ptr_post(b, 4));
cc.ldrsbt(a, ptr_post(b, c));
cc.ldrsbt(a, ptr_post(b, 4));
cc.ldrsh(a, ptr(b, c));
cc.ldrsh(a, ptr_pre(b, c));
cc.ldrsh(a, ptr_post(b, c));
cc.ldrsh(a, ptr(b, 4));
cc.ldrsh(a, ptr_pre(b, 4));
cc.ldrsh(a, ptr_post(b, 4));
cc.ldrsht(a, ptr_post(b, 4));
cc.ldrsht(a, ptr_post(b, c));
cc.ldrt(a, ptr_post(b, c));
cc.ldrt(a, ptr_post(b, 4));
cc.lsl(a, b, 3);
cc.lsl(a, b, c);
cc.lsls(a, b, 3);
cc.lsls(a, b, c);
cc.lsr(a, b, 3);
cc.lsr(a, b, c);
cc.lsrs(a, b, 3);
cc.lsrs(a, b, c);
cc.mla(a, b, c, d);
cc.mlas(a, b, c, d);
cc.mls(a, b, c, d);
cc.mov(a, b, lsl(c));
cc.mov(a, b, lsr(c));
cc.mov(a, b, asr(c));
cc.mov(a, b, ror(c));
cc.mov(a, b, lsl(8));
cc.mov(a, b, lsr(8));
cc.mov(a, b, asr(8));
cc.mov(a, b, ror(8));
cc.mov(a, 0xFF);
cc.mov(a, 0xFF00);
cc.mov(a, 0xFF000000);
cc.mov(a, 0xF000000F);
cc.movs(a, b, lsl(c));
cc.movs(a, b, lsr(c));
cc.movs(a, b, asr(c));
cc.movs(a, b, ror(c));
cc.movs(a, b, lsl(8));
cc.movs(a, b, lsr(8));
cc.movs(a, b, asr(8));
cc.movs(a, b, ror(8));
cc.movs(a, 0xFF);
cc.movs(a, 0xFF00);
cc.movs(a, 0xFF000000);
cc.movs(a, 0xF000000F);
cc.movt(a, 1);
cc.movw(a, 1);
cc.mul(a, b, c);
cc.muls(a, b, c);
cc.mvn(a, b, lsl(c));
cc.mvn(a, b, lsr(c));
cc.mvn(a, b, asr(c));
cc.mvn(a, b, ror(c));
cc.mvn(a, b, lsl(8));
cc.mvn(a, b, lsr(8));
cc.mvn(a, b, asr(8));
cc.mvn(a, b, ror(8));
cc.mvn(a, 0xFF);
cc.mvn(a, 0xFF00);
cc.mvn(a, 0xFF000000);
cc.mvn(a, 0xF000000F);
cc.mvns(a, b, lsl(c));
cc.mvns(a, b, lsr(c));
cc.mvns(a, b, asr(c));
cc.mvns(a, b, ror(c));
cc.mvns(a, b, lsl(8));
cc.mvns(a, b, lsr(8));
cc.mvns(a, b, asr(8));
cc.mvns(a, b, ror(8));
cc.mvns(a, 0xFF);
cc.mvns(a, 0xFF00);
cc.mvns(a, 0xFF000000);
cc.mvns(a, 0xF000000F);
cc.orr(a, b, c, lsl(d));
cc.orr(a, b, c, lsr(d));
cc.orr(a, b, c, asr(d));
cc.orr(a, b, c, ror(d));
cc.orr(a, b, c, lsl(8));
cc.orr(a, b, c, lsr(8));
cc.orr(a, b, c, asr(8));
cc.orr(a, b, c, ror(8));
cc.orr(a, b, 0xFF);
cc.orr(a, b, 0xFF00);
cc.orr(a, b, 0xFF000000);
cc.orr(a, b, 0xF000000F);
cc.orrs(a, b, c, lsl(d));
cc.orrs(a, b, c, lsr(d));
cc.orrs(a, b, c, asr(d));
cc.orrs(a, b, c, ror(d));
cc.orrs(a, b, c, lsl(8));
cc.orrs(a, b, c, lsr(8));
cc.orrs(a, b, c, asr(8));
cc.orrs(a, b, c, ror(8));
cc.orrs(a, b, 0xFF);
cc.orrs(a, b, 0xFF00);
cc.orrs(a, b, 0xFF000000);
cc.orrs(a, b, 0xF000000F);
cc.pkhbt(a, b, c, lsl(8));
cc.pkhtb(a, b, c, asr(8));
cc.qadd(a, b, c);
cc.qadd16(a, b, c);
cc.qadd8(a, b, c);
cc.qasx(a, b, c);
cc.qdadd(a, b, c);
cc.qdsub(a, b, c);
cc.qsax(a, b, c);
cc.qsub(a, b, c);
cc.qsub16(a, b, c);
cc.qsub8(a, b, c);
cc.rbit(a, b);
cc.rev(a, b);
cc.rev16(a, b);
cc.revsh(a, b);
cc.ror(a, b, 3);
cc.ror(a, b, c);
cc.rors(a, b, 3);
cc.rors(a, b, c);
cc.rrx(a, b);
cc.rrxs(a, b);
cc.rsb(a, b, c, lsl(d));
cc.rsb(a, b, c, lsr(d));
cc.rsb(a, b, c, asr(d));
cc.rsb(a, b, c, ror(d));
cc.rsb(a, b, c, lsl(8));
cc.rsb(a, b, c, lsr(8));
cc.rsb(a, b, c, asr(8));
cc.rsb(a, b, c, ror(8));
cc.rsb(a, b, 0xFF);
cc.rsb(a, b, 0xFF00);
cc.rsb(a, b, 0xFF000000);
cc.rsb(a, b, 0xF000000F);
cc.rsbs(a, b, c, lsl(d));
cc.rsbs(a, b, c, lsr(d));
cc.rsbs(a, b, c, asr(d));
cc.rsbs(a, b, c, ror(d));
cc.rsbs(a, b, c, lsl(8));
cc.rsbs(a, b, c, lsr(8));
cc.rsbs(a, b, c, asr(8));
cc.rsbs(a, b, c, ror(8));
cc.rsbs(a, b, 0xFF);
cc.rsbs(a, b, 0xFF00);
cc.rsbs(a, b, 0xFF000000);
cc.rsbs(a, b, 0xF000000F);
cc.rsc(a, b, c, lsl(d));
cc.rsc(a, b, c, lsr(d));
cc.rsc(a, b, c, asr(d));
cc.rsc(a, b, c, ror(d));
cc.rsc(a, b, c, lsl(8));
cc.rsc(a, b, c, lsr(8));
cc.rsc(a, b, c, asr(8));
cc.rsc(a, b, c, ror(8));
cc.rsc(a, b, 0xFF);
cc.rsc(a, b, 0xFF00);
cc.rsc(a, b, 0xFF000000);
cc.rsc(a, b, 0xF000000F);
cc.rscs(a, b, c, lsl(d));
cc.rscs(a, b, c, lsr(d));
cc.rscs(a, b, c, asr(d));
cc.rscs(a, b, c, ror(d));
cc.rscs(a, b, c, lsl(8));
cc.rscs(a, b, c, lsr(8));
cc.rscs(a, b, c, asr(8));
cc.rscs(a, b, c, ror(8));
cc.rscs(a, b, 0xFF);
cc.rscs(a, b, 0xFF00);
cc.rscs(a, b, 0xFF000000);
cc.rscs(a, b, 0xF000000F);
cc.sadd16(a, b, c);
cc.sadd8(a, b, c);
cc.sasx(a, b, c);
cc.sbc(a, b, c, lsl(d));
cc.sbc(a, b, c, lsr(d));
cc.sbc(a, b, c, asr(d));
cc.sbc(a, b, c, ror(d));
cc.sbc(a, b, c, lsl(8));
cc.sbc(a, b, c, lsr(8));
cc.sbc(a, b, c, asr(8));
cc.sbc(a, b, c, ror(8));
cc.sbc(a, b, 0xFF);
cc.sbc(a, b, 0xFF00);
cc.sbc(a, b, 0xFF000000);
cc.sbc(a, b, 0xF000000F);
cc.sbcs(a, b, c, lsl(d));
cc.sbcs(a, b, c, lsr(d));
cc.sbcs(a, b, c, asr(d));
cc.sbcs(a, b, c, ror(d));
cc.sbcs(a, b, c, lsl(8));
cc.sbcs(a, b, c, lsr(8));
cc.sbcs(a, b, c, asr(8));
cc.sbcs(a, b, c, ror(8));
cc.sbcs(a, b, 0xFF);
cc.sbcs(a, b, 0xFF00);
cc.sbcs(a, b, 0xFF000000);
cc.sbcs(a, b, 0xF000000F);
cc.sbfx(a, b, 3, 5);
cc.sdiv(a, b, c);
cc.sel(a, b, c);
cc.shadd16(a, b, c);
cc.shadd8(a, b, c);
cc.shasx(a, b, c);
cc.shsax(a, b, c);
cc.shsub16(a, b, c);
cc.shsub8(a, b, c);
cc.smlabb(a, b, c, d);
cc.smlabt(a, b, c, d);
cc.smlad(a, b, c, d);
cc.smladx(a, b, c, d);
cc.smlal(a, b, c, d);
cc.smlalbb(a, b, c, d);
cc.smlalbt(a, b, c, d);
cc.smlald(a, b, c, d);
cc.smlaldx(a, b, c, d);
cc.smlals(a, b, c, d);
cc.smlaltb(a, b, c, d);
cc.smlaltt(a, b, c, d);
cc.smlatb(a, b, c, d);
cc.smlatt(a, b, c, d);
cc.smlawb(a, b, c, d);
cc.smlawt(a, b, c, d);
cc.smlsd(a, b, c, d);
cc.smlsdx(a, b, c, d);
cc.smlsld(a, b, c, d);
cc.smlsldx(a, b, c, d);
cc.smmla(a, b, c, d);
cc.smmlar(a, b, c, d);
cc.smmls(a, b, c, d);
cc.smmlsr(a, b, c, d);
cc.smmul(a, b, c);
cc.smmulr(a, b, c);
cc.smuad(a, b, c);
cc.smuadx(a, b, c);
cc.smulbb(a, b, c);
cc.smulbt(a, b, c);
cc.smull(a, b, c, d);
cc.smulls(a, b, c, d);
cc.smultb(a, b, c);
cc.smultt(a, b, c);
cc.smulwb(a, b, c);
cc.smulwt(a, b, c);
cc.smusd(a, b, c);
cc.smusdx(a, b, c);
cc.ssat(a, 8, c);
cc.ssat(a, 8, c, lsl(8));
cc.ssat(a, 8, c, asr(8));
cc.ssat16(a, 8, c);
cc.ssax(a, b, c);
cc.ssub16(a, b, c);
cc.ssub8(a, b, c);
cc.str(a, ptr(b, c));
cc.str(a, ptr_pre(b, c));
cc.str(a, ptr_post(b, c));
cc.str(a, ptr(b, 4));
cc.str(a, ptr_pre(b, 4));
cc.str(a, ptr_post(b, 4));
cc.strb(a, ptr(b, c));
cc.strb(a, ptr_pre(b, c));
cc.strb(a, ptr_post(b, c));
cc.strb(a, ptr(b, 4));
cc.strb(a, ptr_pre(b, 4));
cc.strb(a, ptr_post(b, 4));
cc.strbt(a, ptr_post(b, c));
cc.strbt(a, ptr_post(b, 4));
cc.strh(a, ptr(b, c));
cc.strh(a, ptr_pre(b, c));
cc.strh(a, ptr_post(b, c));
cc.strh(a, ptr(b, 4));
cc.strh(a, ptr_pre(b, 4));
cc.strh(a, ptr_post(b, 4));
cc.strht(a, ptr_post(b, c));
cc.strht(a, ptr_post(b, 4));
cc.strt(a, ptr_post(b, c));
cc.strt(a, ptr_post(b, 4));
cc.sub(a, b, c, lsl(d));
cc.sub(a, b, c, lsr(d));
cc.sub(a, b, c, asr(d));
cc.sub(a, b, c, ror(d));
cc.sub(a, b, c, lsl(8));
cc.sub(a, b, c, lsr(8));
cc.sub(a, b, c, asr(8));
cc.sub(a, b, c, ror(8));
cc.sub(a, b, 0xFF);
cc.sub(a, b, 0xFF00);
cc.sub(a, b, 0xFF000000);
cc.sub(a, b, 0xF000000F);
cc.subs(a, b, c, lsl(d));
cc.subs(a, b, c, lsr(d));
cc.subs(a, b, c, asr(d));
cc.subs(a, b, c, ror(d));
cc.subs(a, b, c, lsl(8));
cc.subs(a, b, c, lsr(8));
cc.subs(a, b, c, asr(8));
cc.subs(a, b, c, ror(8));
cc.subs(a, b, 0xFF);
cc.subs(a, b, 0xFF00);
cc.subs(a, b, 0xFF000000);
cc.subs(a, b, 0xF000000F);
cc.sxtab(a, b, c, ror(8));
cc.sxtab16(a, b, c, ror(8));
cc.sxtah(a, b, c, ror(8));
cc.sxtb(a, b, ror(8));
cc.sxtb16(a, b, ror(8));
cc.sxth(a, b, ror(8));
cc.teq(a, b, lsl(c));
cc.teq(a, b, lsr(c));
cc.teq(a, b, asr(c));
cc.teq(a, b, ror(c));
cc.teq(a, b, lsl(8));
cc.teq(a, b, lsr(8));
cc.teq(a, b, asr(8));
cc.teq(a, b, ror(8));
cc.teq(a, 0xFF);
cc.teq(a, 0xFF00);
cc.teq(a, 0xFF000000);
cc.teq(a, 0xF000000F);
cc.tst(a, b, lsl(c));
cc.tst(a, b, lsr(c));
cc.tst(a, b, asr(c));
cc.tst(a, b, ror(c));
cc.tst(a, b, lsl(8));
cc.tst(a, b, lsr(8));
cc.tst(a, b, asr(8));
cc.tst(a, b, ror(8));
cc.tst(a, 0xFF);
cc.tst(a, 0xFF00);
cc.tst(a, 0xFF000000);
cc.tst(a, 0xF000000F);
cc.uadd16(a, b, c);
cc.uadd8(a, b, c);
cc.uasx(a, b, c);
cc.ubfx(a, b, 3, 5);
cc.udiv(a, b, c);
cc.uhadd16(a, b, c);
cc.uhadd8(a, b, c);
cc.uhasx(a, b, c);
cc.uhsax(a, b, c);
cc.uhsub16(a, b, c);
cc.uhsub8(a, b, c);
cc.umaal(a, b, c, d);
cc.umlal(a, b, c, d);
cc.umlals(a, b, c, d);
cc.umull(a, b, c, d);
cc.umulls(a, b, c, d);
cc.uqadd16(a, b, c);
cc.uqadd8(a, b, c);
cc.uqasx(a, b, c);
cc.uqsax(a, b, c);
cc.uqsub16(a, b, c);
cc.uqsub8(a, b, c);
cc.usad8(a, b, c);
cc.usada8(a, b, c, d);
cc.usat(a, 8, c, lsl(8));
cc.usat(a, 8, c, asr(8));
cc.usat16(a, 8, c);
cc.usax(a, b, c);
cc.usub16(a, b, c);
cc.usub8(a, b, c);
cc.uxtab(a, b, c, ror(8));
cc.uxtab16(a, b, c, ror(8));
cc.uxtah(a, b, c, ror(8));
cc.uxtb(a, b, ror(8));
cc.uxtb16(a, b, ror(8));
cc.uxth(a, b, ror(8));
}
static void generateGpSequence(BaseEmitter& emitter, bool emitPrologEpilog) {
if (emitter.isAssembler()) {
a32::Assembler& cc = *emitter.as<a32::Assembler>();
a32::Gp a = a32::r0;
a32::Gp b = a32::r1;
a32::Gp c = a32::r2;
a32::Gp d = a32::r3;
if (emitPrologEpilog) {
FuncDetail func;
func.init(FuncSignature::build<void, void*, const void*, size_t>(), cc.environment());
FuncFrame frame;
frame.init(func);
frame.addDirtyRegs(a, b, c, d);
frame.finalize();
cc.emitProlog(frame);
generateGpSequenceInternal(cc, a, b, c, d);
cc.emitEpilog(frame);
}
else {
generateGpSequenceInternal(cc, a, b, c, d);
}
}
}
template<typename EmitterFn>
static void benchmarkA32Function(Arch arch, uint32_t numIterations, const char* description, const EmitterFn& emitterFn) noexcept {
CodeHolder code;
printf("%s:\n", description);
uint32_t instCount = 0;
#ifndef ASMJIT_NO_BUILDER
instCount = asmjit_perf_utils::calculateInstructionCount<a32::Builder>(code, arch, [&](a32::Builder& emitter) {
emitterFn(emitter, false);
});
#endif
asmjit_perf_utils::bench<a32::Assembler>(code, arch, numIterations, "[raw]", instCount, [&](a32::Assembler& emitter) {
emitterFn(emitter, false);
});
printf("\n");
}
void benchmarkA32Emitters(uint32_t numIterations) {
static const char description[] = "GpSequence (Sequence of GP instructions)";
benchmarkA32Function(Arch::kARM, numIterations, description, [](BaseEmitter& emitter, bool emitPrologEpilog) {
generateGpSequence(emitter, emitPrologEpilog);
});
}
#endif // !ASMJIT_NO_AARCH32

55
asmjit/a32.h Normal file
View File

@@ -0,0 +1,55 @@
// 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_A32_H_INCLUDED
#define ASMJIT_A32_H_INCLUDED
//! \addtogroup asmjit_a32
//!
//! ### Emitters
//!
//! - \ref a32::Assembler - AArch32 assembler (must read, provides examples).
//! - \ref a32::Builder - AArch32 builder.
//! - \ref a32::Compiler - AArch32 compiler.
//! - \ref a32::Emitter - AArch32 emitter (abstract).
//!
//! ### Supported Instructions
//!
//! - Emitters:
//! - \ref a32::EmitterExplicitT - Provides all instructions that use explicit operands, provides also utility
//! functions. The member functions provided are part of all AArch32 emitters.
//!
//! - Instruction representation:
//! - \ref a32::Inst::Id - instruction identifiers.
//!
//! ### Register Operands
//!
//! - \ref arm::Reg - Base class of any AArch32/AArch64 register.
//! - \ref a32::Gp - 32-bit general purpose register (AArch32)
//! - \ref arm::Vec - Vector (SIMD) register:
//! - \ref arm::VecS - 32-bit SIMD register.
//! - \ref arm::VecD - 64-bit SIMD register.
//! - \ref arm::VecV - 128-bit SIMD register.
//!
//! ### Memory Operands
//!
//! - \ref arm::Mem - AArch32/AArch64 memory operand that provides support for all ARM addressing features
//! including base, index, pre/post increment, and ARM-specific shift addressing and index extending.
//!
//! ### Other
//!
//! - \ref arm::Shift - Shift operation and value.
//! - \ref arm::DataType - Data type that is part of an instruction in AArch32 mode.
//! - \ref a32::Utils - Utilities that can help during code generation for AArch32.
#include <asmjit/arm.h>
#include <asmjit/arm/a32assembler.h>
#include <asmjit/arm/a32builder.h>
#include <asmjit/arm/a32emitter.h>
#include <asmjit/arm/a32globals.h>
#include <asmjit/arm/a32operand.h>
#endif // ASMJIT_A32_H_INCLUDED

View File

@@ -0,0 +1,76 @@
// 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_ARM_A32ARCHTRAITS_P_H_INCLUDED
#define ASMJIT_ARM_A32ARCHTRAITS_P_H_INCLUDED
#include <asmjit/core/archtraits.h>
#include <asmjit/core/misc_p.h>
#include <asmjit/core/type.h>
#include <asmjit/arm/a32globals.h>
#include <asmjit/arm/a32operand.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \cond INTERNAL
//! \addtogroup asmjit_a32
//! \{
static const constexpr ArchTraits a32_arch_traits = {
// SP/FP/LR/PC.
13, 11, 14, 15,
// Reserved.
{ 0u, 0u, 0u },
// HW stack alignment (AArch32 requires stack aligned to 4 bytes at HW level).
4,
// Min/max stack offset.
0, 0, // TODO: ARM32
// Supported register types.
0u | (1u << uint32_t(RegType::kGp32 ))
| (1u << uint32_t(RegType::kVec32 ))
| (1u << uint32_t(RegType::kVec64 ))
| (1u << uint32_t(RegType::kVec128)),
// Instruction hints [Gp, Vec, ExtraVirt2, ExtraVirt3].
{{
InstHints::kPushPop,
InstHints::kPushPop,
InstHints::kNoHints,
InstHints::kNoHints
}},
// TypeIdToRegType.
#define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kGp32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kVec32 : \
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kVec64 : RegType::kNone)
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
#undef V
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
{
ArchTypeNameId::kByte,
ArchTypeNameId::kHWord,
ArchTypeNameId::kWord,
ArchTypeNameId::kXWord
}
};
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32ARCHTRAITS_P_H_INCLUDED

11016
asmjit/arm/a32assembler.cpp Normal file

File diff suppressed because it is too large Load Diff

69
asmjit/arm/a32assembler.h Normal file
View File

@@ -0,0 +1,69 @@
// 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_ARM_A32ASSEMBLER_H_INCLUDED
#define ASMJIT_ARM_A32ASSEMBLER_H_INCLUDED
#include <asmjit/core/assembler.h>
#include <asmjit/arm/a32emitter.h>
#include <asmjit/arm/a32operand.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \addtogroup asmjit_a32
//! \{
//! AArch32 assembler implementation.
class ASMJIT_VIRTAPI Assembler
: public BaseAssembler,
public EmitterExplicitT<Assembler> {
public:
typedef BaseAssembler Base;
//! \name Construction & Destruction
//! \{
ASMJIT_API Assembler(CodeHolder* code = nullptr) noexcept;
ASMJIT_API ~Assembler() noexcept override;
//! \}
//! \name Accessors
//! \{
//! Gets whether the current ARM mode is THUMB (alternative to 32-bit ARM encoding).
ASMJIT_INLINE_NODEBUG bool is_in_thumb_mode() const noexcept { return _environment.is_arch_thumb(); }
//! \}
//! \name Emit
//! \{
ASMJIT_API Error _emit(InstId inst_id, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override;
//! \}
//! \name Align
//! \{
ASMJIT_API Error align(AlignMode align_mode, uint32_t alignment) override;
//! \}
//! \name Events
//! \{
ASMJIT_API Error on_attach(CodeHolder& code) noexcept override;
ASMJIT_API Error on_detach(CodeHolder& code) noexcept override;
//! \}
};
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32ASSEMBLER_H_INCLUDED

58
asmjit/arm/a32builder.cpp Normal file
View File

@@ -0,0 +1,58 @@
// 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 <asmjit/core/api-build_p.h>
#if !defined(ASMJIT_NO_AARCH32) && !defined(ASMJIT_NO_BUILDER)
#include <asmjit/arm/a32assembler.h>
#include <asmjit/arm/a32builder.h>
#include <asmjit/arm/a32emithelper_p.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
// a32::Builder - Construction & Destruction
// =========================================
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
_arch_mask = uint64_t(1) << uint32_t(Arch::kARM ) |
uint64_t(1) << uint32_t(Arch::kARM_BE ) |
uint64_t(1) << uint32_t(Arch::kThumb ) |
uint64_t(1) << uint32_t(Arch::kThumb_BE) ;
if (code)
code->attach(this);
}
Builder::~Builder() noexcept {}
// a32::Builder - Events
// =====================
Error Builder::on_attach(CodeHolder& code) noexcept {
ASMJIT_PROPAGATE(Base::on_attach(code));
_instruction_alignment = _environment.is_arch_thumb() ? uint8_t(2) : uint8_t(4);
_instruction_alignment = uint8_t(4);
update_emitter_funcs(this);
return Error::kOk;
}
Error Builder::on_detach(CodeHolder& code) noexcept {
return Base::on_detach(code);
}
// a32::Builder - Finalize
// =======================
Error Builder::finalize() {
ASMJIT_PROPAGATE(run_passes());
Assembler a(_code);
a.add_encoding_options(encoding_options());
a.add_diagnostic_options(diagnostic_options());
return serialize_to(&a);
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH32 && !ASMJIT_NO_BUILDER

57
asmjit/arm/a32builder.h Normal file
View File

@@ -0,0 +1,57 @@
// 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_ARM_A32BUILDER_H_INCLUDED
#define ASMJIT_ARM_A32BUILDER_H_INCLUDED
#include <asmjit/core/api-config.h>
#ifndef ASMJIT_NO_BUILDER
#include <asmjit/core/builder.h>
#include <asmjit/arm/a32emitter.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \addtogroup asmjit_a32
//! \{
//! AArch32 builder implementation.
class ASMJIT_VIRTAPI Builder
: public BaseBuilder,
public EmitterExplicitT<Builder> {
public:
ASMJIT_NONCOPYABLE(Builder)
typedef BaseBuilder Base;
//! \name Construction & Destruction
//! \{
ASMJIT_API explicit Builder(CodeHolder* code = nullptr) noexcept;
ASMJIT_API ~Builder() noexcept override;
//! \}
//! \name Events
//! \{
ASMJIT_API Error on_attach(CodeHolder& code) noexcept override;
ASMJIT_API Error on_detach(CodeHolder& code) noexcept override;
//! \}
//! \name Finalize
//! \{
ASMJIT_API Error finalize() override;
//! \}
};
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_BUILDER
#endif // ASMJIT_ARM_A32BUILDER_H_INCLUDED

View File

@@ -0,0 +1,395 @@
// 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 <asmjit/core/api-build_p.h>
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/core/formatter.h>
#include <asmjit/core/funcargscontext_p.h>
#include <asmjit/core/string.h>
#include <asmjit/core/type.h>
#include <asmjit/support/support.h>
#include <asmjit/arm/a32emithelper_p.h>
#include <asmjit/arm/a32formatter_p.h>
#include <asmjit/arm/a32operand.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
// a32::EmitHelper - Emit Operations
// =================================
ASMJIT_FAVOR_SIZE Error EmitHelper::emit_reg_move(
const Operand_& dst_,
const Operand_& src_, TypeId type_id, const char* comment) {
Emitter* emitter = _emitter->as<Emitter>();
// Invalid or abstract TypeIds are not allowed.
ASMJIT_ASSERT(TypeUtils::is_valid(type_id) && !TypeUtils::is_abstract(type_id));
emitter->set_inline_comment(comment);
if (dst_.is_reg() && src_.is_mem()) {
Reg dst(dst_.as<Reg>());
Mem src(src_.as<Mem>());
switch (type_id) {
case TypeId::kInt8:
case TypeId::kUInt8:
return emitter->ldrb(dst.as<Gp>(), src);
case TypeId::kInt16:
case TypeId::kUInt16:
return emitter->ldrh(dst.as<Gp>(), src);
case TypeId::kInt32:
case TypeId::kUInt32:
return emitter->ldr(dst.as<Gp>(), src);
default: {
if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id))
return emitter->vldr_32(dst.as<Vec>().s(), src);
if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id))
return emitter->vldr_64(dst.as<Vec>().d(), src);
// TODO: AArch32.
// if (TypeUtils::is_vec128(type_id))
// return emitter->vldr(dst.as<Vec>().q(), src);
break;
}
}
}
if (dst_.is_mem() && src_.is_reg()) {
Mem dst(dst_.as<Mem>());
Reg src(src_.as<Reg>());
switch (type_id) {
case TypeId::kInt8:
case TypeId::kUInt8:
return emitter->strb(src.as<Gp>(), dst);
case TypeId::kInt16:
case TypeId::kUInt16:
return emitter->strh(src.as<Gp>(), dst);
case TypeId::kInt32:
case TypeId::kUInt32:
return emitter->str(src.as<Gp>(), dst);
default: {
if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id))
return emitter->vstr_32(src.as<Vec>().s(), dst);
if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id))
return emitter->vstr_64(src.as<Vec>().d(), dst);
// TODO: AArch32
// if (TypeUtils::isVec128(type_id))
// return emitter->vstr(src.as<Vec>().q(), dst);
break;
}
}
}
if (dst_.is_reg() && src_.is_reg()) {
Reg dst(dst_.as<Reg>());
Reg src(src_.as<Reg>());
switch (type_id) {
case TypeId::kInt8:
case TypeId::kUInt8:
case TypeId::kInt16:
case TypeId::kUInt16:
case TypeId::kInt32:
case TypeId::kUInt32:
return emitter->mov(src.as<Gp>(), dst.as<Gp>());
default: {
if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id))
return emitter->vmov(dst.as<Vec>().s(), src.as<Vec>().s());
if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id))
return emitter->vmov(dst.as<Vec>().d(), src.as<Vec>().d());
if (TypeUtils::is_vec128(type_id))
return emitter->vmov(dst.as<Vec>().q(), src.as<Vec>().q());
break;
}
}
}
emitter->set_inline_comment(nullptr);
return make_error(Error::kInvalidState);
}
Error EmitHelper::emit_reg_swap(
const Reg& a,
const Reg& b, const char* comment) {
Support::maybe_unused(a, b, comment);
return make_error(Error::kInvalidState);
}
Error EmitHelper::emit_arg_move(
const Reg& dst_, TypeId dst_type_id,
const Operand_& src_, TypeId src_type_id, const char* comment) {
// TODO: AArch32 - EmitArgMove is unfinished.
Support::maybe_unused(dst_, dst_type_id, src_, src_type_id, comment);
return make_error(Error::kInvalidState);
}
// a32::EmitHelper - Emit Prolog & Epilog
// ======================================
struct LoadStoreInstructions {
InstId singleInstId;
InstId pairInstId;
};
/*
struct PrologEpilogInfo {
struct RegPair {
uint8_t ids[2];
uint16_t offset;
};
struct GroupData {
RegPair pairs[16];
uint32_t pairCount;
};
Support::Array<GroupData, 2> groups;
uint32_t sizeTotal;
Error init(const FuncFrame& frame) noexcept {
uint32_t offset = 0;
for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
GroupData& data = groups[group];
uint32_t n = 0;
uint32_t pairCount = 0;
RegPair* pairs = data.pairs;
uint32_t slotSize = frame.saveRestoreRegSize(group);
uint32_t savedRegs = frame.savedRegs(group);
if (group == RegGroup::kGp && frame.hasPreservedFP()) {
// Must be at the beginning of the push/pop sequence.
ASMJIT_ASSERT(pairCount == 0);
pairs[0].offset = uint16_t(offset);
pairs[0].ids[0] = Gp::kIdFp;
pairs[0].ids[1] = Gp::kIdLr;
offset += slotSize * 2;
pairCount++;
savedRegs &= ~Support::bitMask(Gp::kIdFp, Gp::kIdLr);
}
Support::BitWordIterator<uint32_t> it(savedRegs);
while (it.hasNext()) {
pairs[pairCount].ids[n] = uint8_t(it.next());
if (++n == 2) {
pairs[pairCount].offset = uint16_t(offset);
offset += slotSize * 2;
n = 0;
pairCount++;
}
}
if (n == 1) {
pairs[pairCount].ids[1] = uint8_t(BaseReg::kIdBad);
pairs[pairCount].offset = uint16_t(offset);
offset += slotSize * 2;
pairCount++;
}
data.pairCount = pairCount;
}
sizeTotal = offset;
return kErrorOk;
}
};
ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
Emitter* emitter = _emitter->as<Emitter>();
PrologEpilogInfo pei;
ASMJIT_PROPAGATE(pei.init(frame));
static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
{ Inst::kIdStr , Inst::kIdStp },
{ Inst::kIdStr_v, Inst::kIdStp_v }
}};
uint32_t adjustInitialOffset = pei.sizeTotal;
for (RegGroup group : Support::EnumValues<RegGroup, RegGroup::kGp, RegGroup::kVec>{}) {
const PrologEpilogInfo::GroupData& data = pei.groups[group];
uint32_t pairCount = data.pairCount;
Reg regs[2] = { groupRegs[group], groupRegs[group] };
Mem mem = ptr(sp);
const LoadStoreInstructions& insts = groupInsts[group];
for (uint32_t i = 0; i < pairCount; i++) {
const PrologEpilogInfo::RegPair& pair = data.pairs[i];
regs[0].setId(pair.ids[0]);
regs[1].setId(pair.ids[1]);
mem.setOffsetLo32(pair.offset);
if (pair.offset == 0 && adjustInitialOffset) {
mem.setOffset(-int(adjustInitialOffset));
mem.makePreIndex();
}
if (pair.ids[1] == BaseReg::kIdBad)
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
else
ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
mem.resetToFixedOffset();
if (i == 0 && frame.hasPreservedFP()) {
ASMJIT_PROPAGATE(emitter->mov(x29, sp));
}
}
}
if (frame.hasStackAdjustment()) {
uint32_t adj = frame.stackAdjustment();
if (adj <= 0xFFFu) {
ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj));
}
else if (adj <= 0xFFFFFFu) {
// TODO: [ARM] Prolog - we must touch the pages otherwise it's undefined.
ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0x000FFFu));
ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0xFFF000u));
}
else {
return make_error(Error::kInvalidState);
}
}
return kErrorOk;
}
// TODO: [ARM] Emit epilog.
ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
Emitter* emitter = _emitter->as<Emitter>();
PrologEpilogInfo pei;
ASMJIT_PROPAGATE(pei.init(frame));
static const Support::Array<Reg, 2> groupRegs = {{ x0, d0 }};
static const Support::Array<LoadStoreInstructions, 2> groupInsts = {{
{ Inst::kIdLdr , Inst::kIdLdp },
{ Inst::kIdLdr_v, Inst::kIdLdp_v }
}};
uint32_t adjustInitialOffset = pei.sizeTotal;
if (frame.hasStackAdjustment()) {
uint32_t adj = frame.stackAdjustment();
if (adj <= 0xFFFu) {
ASMJIT_PROPAGATE(emitter->add(sp, sp, adj));
}
else if (adj <= 0xFFFFFFu) {
ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0x000FFFu));
ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0xFFF000u));
}
else {
return make_error(Error::kInvalidState);
}
}
for (int g = 1; g >= 0; g--) {
RegGroup group = RegGroup(g);
const PrologEpilogInfo::GroupData& data = pei.groups[group];
uint32_t pairCount = data.pairCount;
Reg regs[2] = { groupRegs[group], groupRegs[group] };
Mem mem = ptr(sp);
const LoadStoreInstructions& insts = groupInsts[group];
for (int i = int(pairCount) - 1; i >= 0; i--) {
const PrologEpilogInfo::RegPair& pair = data.pairs[i];
regs[0].setId(pair.ids[0]);
regs[1].setId(pair.ids[1]);
mem.setOffsetLo32(pair.offset);
if (pair.offset == 0 && adjustInitialOffset) {
mem.setOffset(int(adjustInitialOffset));
mem.makePostIndex();
}
if (pair.ids[1] == BaseReg::kIdBad)
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
else
ASMJIT_PROPAGATE(emitter->emit(insts.pairInstId, regs[0], regs[1], mem));
mem.resetToFixedOffset();
}
}
ASMJIT_PROPAGATE(emitter->ret(x30));
return kErrorOk;
}
*/
static Error ASMJIT_CDECL Emitter_emit_prolog(BaseEmitter* emitter, const FuncFrame& frame) {
// EmitHelper emitHelper(emitter);
// return emitHelper.emitProlog(frame);
Support::maybe_unused(emitter, frame);
return make_error(Error::kInvalidState);
}
static Error ASMJIT_CDECL Emitter_emit_epilog(BaseEmitter* emitter, const FuncFrame& frame) {
// EmitHelper emitHelper(emitter);
// return emitHelper.emitEpilog(frame);
Support::maybe_unused(emitter, frame);
return make_error(Error::kInvalidState);
}
static Error ASMJIT_CDECL Emitter_emit_args_assignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) {
// EmitHelper emitHelper(emitter);
// return emitHelper.emitArgsAssignment(frame, args);
Support::maybe_unused(emitter, frame, args);
return make_error(Error::kInvalidState);
}
void assignEmitterFuncs(BaseEmitter* emitter) {
emitter->_funcs.emit_prolog = Emitter_emit_prolog;
emitter->_funcs.emit_epilog = Emitter_emit_epilog;
emitter->_funcs.emit_args_assignment = Emitter_emit_args_assignment;
#ifndef ASMJIT_NO_LOGGING
emitter->_funcs.format_instruction = FormatterInternal::format_instruction;
#endif
#ifndef ASMJIT_NO_VALIDATION
// TODO: AArch32.
// emitter->_funcs.validate = InstInternal::validate;
#endif
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH32

View File

@@ -0,0 +1,53 @@
// 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_ARM_A32EMITHELPER_P_H_INCLUDED
#define ASMJIT_ARM_A32EMITHELPER_P_H_INCLUDED
#include <asmjit/core/api-config.h>
#include <asmjit/core/emithelper_p.h>
#include <asmjit/core/func.h>
#include <asmjit/arm/a32emitter.h>
#include <asmjit/arm/a32operand.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \cond INTERNAL
//! \addtogroup asmjit_a32
//! \{
class EmitHelper : public BaseEmitHelper {
public:
ASMJIT_INLINE_NODEBUG explicit EmitHelper(BaseEmitter* emitter = nullptr) noexcept
: BaseEmitHelper(emitter) {}
ASMJIT_INLINE_NODEBUG ~EmitHelper() noexcept override = default;
Error emit_reg_move(
const Operand_& dst_,
const Operand_& src_, TypeId type_id, const char* comment = nullptr) override;
Error emit_reg_swap(
const Reg& a,
const Reg& b, const char* comment = nullptr) override;
Error emit_arg_move(
const Reg& dst_, TypeId dst_type_id,
const Operand_& src_, TypeId src_type_id, const char* comment = nullptr) override;
Error emit_prolog(const FuncFrame& frame);
Error emit_epilog(const FuncFrame& frame);
};
[[maybe_unused]]
static inline void update_emitter_funcs(BaseEmitter* emitter) noexcept { Support::maybe_unused(emitter); }
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32EMITHELPER_P_H_INCLUDED

1603
asmjit/arm/a32emitter.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
// 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 <asmjit/core/api-build_p.h>
#if !defined(ASMJIT_NO_AARCH32) && !defined(ASMJIT_NO_LOGGING)
#include <asmjit/core/misc_p.h>
#include <asmjit/support/support.h>
#include <asmjit/arm/a32formatter_p.h>
#include <asmjit/arm/a32instapi_p.h>
#include <asmjit/arm/a32instdb_p.h>
#include <asmjit/arm/a32operand.h>
#ifndef ASMJIT_NO_COMPILER
#include <asmjit/core/compiler.h>
#endif
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
// a32::FormatterInternal - Format Instruction
// ===========================================
ASMJIT_FAVOR_SIZE Error FormatterInternal::format_instruction(
String& sb,
FormatFlags format_flags,
const BaseEmitter* emitter,
Arch arch,
const BaseInst& inst, Span<const Operand_> operands) noexcept {
Support::maybe_unused(arch);
// Format instruction options and instruction mnemonic.
InstId inst_id = inst.real_id();
if (inst_id < Inst::_kIdCount) {
InstStringifyOptions stringifyOptions =
Support::test(format_flags, FormatFlags::kShowAliases)
? InstStringifyOptions::kAliases
: InstStringifyOptions::kNone;
ASMJIT_PROPAGATE(InstInternal::inst_id_to_string(inst_id, stringifyOptions, sb));
}
else {
ASMJIT_PROPAGATE(sb.append_format("[InstId=#%u]", unsigned(inst_id)));
}
CondCode cc = inst.arm_cond_code();
if (cc != CondCode::kAL) {
ASMJIT_PROPAGATE(sb.append('.'));
ASMJIT_PROPAGATE(format_cond_code(sb, cc));
}
// Format instruction operands.
for (size_t i = 0; i < operands.size(); i++) {
const Operand_& op = operands[i];
if (op.is_none())
break;
ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
ASMJIT_PROPAGATE(format_operand(sb, format_flags, emitter, arch, op));
}
return kErrorOk;
}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH32 && !ASMJIT_NO_LOGGING

View File

@@ -0,0 +1,42 @@
// 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_ARM_A32FORMATTER_P_H_INCLUDED
#define ASMJIT_ARM_A32FORMATTER_P_H_INCLUDED
#include <asmjit/core/api-config.h>
#ifndef ASMJIT_NO_LOGGING
#include <asmjit/core/formatter.h>
#include <asmjit/core/string.h>
#include <asmjit/arm/armformatter_p.h>
#include <asmjit/arm/a32globals.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \cond INTERNAL
//! \addtogroup asmjit_a32
//! \{
namespace FormatterInternal {
using namespace arm::FormatterInternal;
Error ASMJIT_CDECL format_instruction(
String& sb,
FormatFlags format_flags,
const BaseEmitter* emitter,
Arch arch,
const BaseInst& inst, Span<const Operand_> operands) noexcept;
} // {FormatterInternal}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_LOGGING
#endif // ASMJIT_ARM_A32FORMATTER_P_H_INCLUDED

531
asmjit/arm/a32globals.h Normal file
View File

@@ -0,0 +1,531 @@
// 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_ARM_A32GLOBALS_H_INCLUDED
#define ASMJIT_ARM_A32GLOBALS_H_INCLUDED
#include <asmjit/arm/armglobals.h>
//! \namespace asmjit::a32
//! \ingroup asmjit_a32
//!
//! AArch32 backend.
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \addtogroup asmjit_a32
//! \{
//! ARM32/THUMB instruction.
//!
//! \note Only used to hold ARM-specific enumerations and static functions.
struct Inst {
//! Instruction id.
enum Id : uint32_t {
// ${a32::InstId:Begin}
// ------------------- Automatically generated, do not edit -------------------
kIdNone = 0, //!< Instruction '<none>'.
kIdAdc, //!< Instruction 'adc'.
kIdAdcs, //!< Instruction 'adcs'.
kIdAdd, //!< Instruction 'add'.
kIdAdds, //!< Instruction 'adds'.
kIdAdr, //!< Instruction 'adr'.
kIdAesd, //!< Instruction 'aesd' {AES}.
kIdAese, //!< Instruction 'aese' {AES}.
kIdAesimc, //!< Instruction 'aesimc' {AES}.
kIdAesmc, //!< Instruction 'aesmc' {AES}.
kIdAnd, //!< Instruction 'and'.
kIdAnds, //!< Instruction 'ands'.
kIdAsr, //!< Instruction 'asr'.
kIdAsrs, //!< Instruction 'asrs'.
kIdB, //!< Instruction 'b'.
kIdBfc, //!< Instruction 'bfc'.
kIdBfi, //!< Instruction 'bfi'.
kIdBic, //!< Instruction 'bic'.
kIdBics, //!< Instruction 'bics'.
kIdBkpt, //!< Instruction 'bkpt'.
kIdBl, //!< Instruction 'bl'.
kIdBlx, //!< Instruction 'blx'.
kIdBx, //!< Instruction 'bx'.
kIdBxj, //!< Instruction 'bxj'.
kIdCbnz, //!< Instruction 'cbnz' (THUMB).
kIdCbz, //!< Instruction 'cbz' (THUMB).
kIdClrbhb, //!< Instruction 'clrbhb' {CLRBHB}.
kIdClrex, //!< Instruction 'clrex'.
kIdClz, //!< Instruction 'clz'.
kIdCmn, //!< Instruction 'cmn'.
kIdCmp, //!< Instruction 'cmp'.
kIdCps, //!< Instruction 'cps' (ARM).
kIdCpsid, //!< Instruction 'cpsid' (ARM).
kIdCpsie, //!< Instruction 'cpsie' (ARM).
kIdCrc32b, //!< Instruction 'crc32b' {CRC32}.
kIdCrc32cb, //!< Instruction 'crc32cb' {CRC32}.
kIdCrc32ch, //!< Instruction 'crc32ch' {CRC32}.
kIdCrc32cw, //!< Instruction 'crc32cw' {CRC32}.
kIdCrc32h, //!< Instruction 'crc32h' {CRC32}.
kIdCrc32w, //!< Instruction 'crc32w' {CRC32}.
kIdCsdb, //!< Instruction 'csdb'.
kIdDbg, //!< Instruction 'dbg' {ARMv8-}.
kIdDcps1, //!< Instruction 'dcps1' (THUMB).
kIdDcps2, //!< Instruction 'dcps2' (THUMB).
kIdDcps3, //!< Instruction 'dcps3' (THUMB).
kIdDmb, //!< Instruction 'dmb'.
kIdDsb, //!< Instruction 'dsb'.
kIdEor, //!< Instruction 'eor'.
kIdEors, //!< Instruction 'eors'.
kIdEret, //!< Instruction 'eret' (ARM).
kIdEsb, //!< Instruction 'esb' {RAS}.
kIdHlt, //!< Instruction 'hlt'.
kIdHvc, //!< Instruction 'hvc' (ARM).
kIdIsb, //!< Instruction 'isb'.
kIdIt, //!< Instruction 'it' (THUMB).
kIdIte, //!< Instruction 'ite' (THUMB).
kIdItee, //!< Instruction 'itee' (THUMB).
kIdIteee, //!< Instruction 'iteee' (THUMB).
kIdIteet, //!< Instruction 'iteet' (THUMB).
kIdItet, //!< Instruction 'itet' (THUMB).
kIdItete, //!< Instruction 'itete' (THUMB).
kIdItett, //!< Instruction 'itett' (THUMB).
kIdItt, //!< Instruction 'itt' (THUMB).
kIdItte, //!< Instruction 'itte' (THUMB).
kIdIttee, //!< Instruction 'ittee' (THUMB).
kIdIttet, //!< Instruction 'ittet' (THUMB).
kIdIttt, //!< Instruction 'ittt' (THUMB).
kIdIttte, //!< Instruction 'ittte' (THUMB).
kIdItttt, //!< Instruction 'itttt' (THUMB).
kIdLda, //!< Instruction 'lda'.
kIdLdab, //!< Instruction 'ldab'.
kIdLdaex, //!< Instruction 'ldaex'.
kIdLdaexb, //!< Instruction 'ldaexb'.
kIdLdaexd, //!< Instruction 'ldaexd'.
kIdLdaexh, //!< Instruction 'ldaexh'.
kIdLdah, //!< Instruction 'ldah'.
kIdLdmda, //!< Instruction 'ldmda' (ARM).
kIdLdmdb, //!< Instruction 'ldmdb'.
kIdLdmia, //!< Instruction 'ldmia'.
kIdLdmib, //!< Instruction 'ldmib' (ARM).
kIdLdr, //!< Instruction 'ldr'.
kIdLdrb, //!< Instruction 'ldrb'.
kIdLdrbt, //!< Instruction 'ldrbt'.
kIdLdrd, //!< Instruction 'ldrd'.
kIdLdrex, //!< Instruction 'ldrex'.
kIdLdrexb, //!< Instruction 'ldrexb'.
kIdLdrexd, //!< Instruction 'ldrexd'.
kIdLdrexh, //!< Instruction 'ldrexh'.
kIdLdrh, //!< Instruction 'ldrh'.
kIdLdrht, //!< Instruction 'ldrht'.
kIdLdrsb, //!< Instruction 'ldrsb'.
kIdLdrsbt, //!< Instruction 'ldrsbt'.
kIdLdrsh, //!< Instruction 'ldrsh'.
kIdLdrsht, //!< Instruction 'ldrsht'.
kIdLdrt, //!< Instruction 'ldrt'.
kIdLsl, //!< Instruction 'lsl'.
kIdLsls, //!< Instruction 'lsls'.
kIdLsr, //!< Instruction 'lsr'.
kIdLsrs, //!< Instruction 'lsrs'.
kIdMcr, //!< Instruction 'mcr' {ARMv6T2+}.
kIdMcr2, //!< Instruction 'mcr2' {ARMv6T2+}.
kIdMcrr, //!< Instruction 'mcrr' {ARMv6T2+}.
kIdMcrr2, //!< Instruction 'mcrr2' {ARMv6T2+}.
kIdMla, //!< Instruction 'mla'.
kIdMlas, //!< Instruction 'mlas' (ARM).
kIdMls, //!< Instruction 'mls'.
kIdMov, //!< Instruction 'mov'.
kIdMovs, //!< Instruction 'movs'.
kIdMovt, //!< Instruction 'movt'.
kIdMovw, //!< Instruction 'movw'.
kIdMrc, //!< Instruction 'mrc'.
kIdMrc2, //!< Instruction 'mrc2'.
kIdMrrc, //!< Instruction 'mrrc'.
kIdMrrc2, //!< Instruction 'mrrc2'.
kIdMrs, //!< Instruction 'mrs'.
kIdMsr, //!< Instruction 'msr'.
kIdMul, //!< Instruction 'mul'.
kIdMuls, //!< Instruction 'muls'.
kIdMvn, //!< Instruction 'mvn'.
kIdMvns, //!< Instruction 'mvns'.
kIdNop, //!< Instruction 'nop'.
kIdOrn, //!< Instruction 'orn' (THUMB).
kIdOrns, //!< Instruction 'orns' (THUMB).
kIdOrr, //!< Instruction 'orr'.
kIdOrrs, //!< Instruction 'orrs'.
kIdPkhbt, //!< Instruction 'pkhbt'.
kIdPkhtb, //!< Instruction 'pkhtb'.
kIdPld, //!< Instruction 'pld'.
kIdPldw, //!< Instruction 'pldw' {MP}.
kIdPli, //!< Instruction 'pli'.
kIdPop, //!< Instruction 'pop'.
kIdPssbb, //!< Instruction 'pssbb'.
kIdPush, //!< Instruction 'push'.
kIdQadd, //!< Instruction 'qadd'.
kIdQadd16, //!< Instruction 'qadd16'.
kIdQadd8, //!< Instruction 'qadd8'.
kIdQasx, //!< Instruction 'qasx'.
kIdQdadd, //!< Instruction 'qdadd'.
kIdQdsub, //!< Instruction 'qdsub'.
kIdQsax, //!< Instruction 'qsax'.
kIdQsub, //!< Instruction 'qsub'.
kIdQsub16, //!< Instruction 'qsub16'.
kIdQsub8, //!< Instruction 'qsub8'.
kIdRbit, //!< Instruction 'rbit'.
kIdRev, //!< Instruction 'rev'.
kIdRev16, //!< Instruction 'rev16'.
kIdRevsh, //!< Instruction 'revsh'.
kIdRfeda, //!< Instruction 'rfeda' (ARM).
kIdRfedb, //!< Instruction 'rfedb' (ARM).
kIdRfeia, //!< Instruction 'rfeia' (ARM).
kIdRfeib, //!< Instruction 'rfeib' (ARM).
kIdRor, //!< Instruction 'ror'.
kIdRors, //!< Instruction 'rors'.
kIdRrx, //!< Instruction 'rrx'.
kIdRrxs, //!< Instruction 'rrxs'.
kIdRsb, //!< Instruction 'rsb'.
kIdRsbs, //!< Instruction 'rsbs'.
kIdRsc, //!< Instruction 'rsc' (ARM).
kIdRscs, //!< Instruction 'rscs' (ARM).
kIdSadd16, //!< Instruction 'sadd16'.
kIdSadd8, //!< Instruction 'sadd8'.
kIdSasx, //!< Instruction 'sasx'.
kIdSb, //!< Instruction 'sb' {SB}.
kIdSbc, //!< Instruction 'sbc'.
kIdSbcs, //!< Instruction 'sbcs'.
kIdSbfx, //!< Instruction 'sbfx'.
kIdSdiv, //!< Instruction 'sdiv' {IDIVA & IDIVT}.
kIdSel, //!< Instruction 'sel'.
kIdSetend, //!< Instruction 'setend' {ARMv8-}.
kIdSetpan, //!< Instruction 'setpan' {PAN}.
kIdSev, //!< Instruction 'sev'.
kIdSevl, //!< Instruction 'sevl'.
kIdSha1c, //!< Instruction 'sha1c' {SHA1}.
kIdSha1h, //!< Instruction 'sha1h' {SHA1}.
kIdSha1m, //!< Instruction 'sha1m' {SHA1}.
kIdSha1p, //!< Instruction 'sha1p' {SHA1}.
kIdSha1su0, //!< Instruction 'sha1su0' {SHA1}.
kIdSha1su1, //!< Instruction 'sha1su1' {SHA1}.
kIdSha256h, //!< Instruction 'sha256h' {SHA256}.
kIdSha256h2, //!< Instruction 'sha256h2' {SHA256}.
kIdSha256su0, //!< Instruction 'sha256su0' {SHA256}.
kIdSha256su1, //!< Instruction 'sha256su1' {SHA256}.
kIdShadd16, //!< Instruction 'shadd16'.
kIdShadd8, //!< Instruction 'shadd8'.
kIdShasx, //!< Instruction 'shasx'.
kIdShsax, //!< Instruction 'shsax'.
kIdShsub16, //!< Instruction 'shsub16'.
kIdShsub8, //!< Instruction 'shsub8'.
kIdSmc, //!< Instruction 'smc' {SECURITY}.
kIdSmlabb, //!< Instruction 'smlabb'.
kIdSmlabt, //!< Instruction 'smlabt'.
kIdSmlad, //!< Instruction 'smlad'.
kIdSmladx, //!< Instruction 'smladx'.
kIdSmlal, //!< Instruction 'smlal'.
kIdSmlalbb, //!< Instruction 'smlalbb'.
kIdSmlalbt, //!< Instruction 'smlalbt'.
kIdSmlald, //!< Instruction 'smlald'.
kIdSmlaldx, //!< Instruction 'smlaldx'.
kIdSmlals, //!< Instruction 'smlals' (ARM).
kIdSmlaltb, //!< Instruction 'smlaltb'.
kIdSmlaltt, //!< Instruction 'smlaltt'.
kIdSmlatb, //!< Instruction 'smlatb'.
kIdSmlatt, //!< Instruction 'smlatt'.
kIdSmlawb, //!< Instruction 'smlawb'.
kIdSmlawt, //!< Instruction 'smlawt'.
kIdSmlsd, //!< Instruction 'smlsd'.
kIdSmlsdx, //!< Instruction 'smlsdx'.
kIdSmlsld, //!< Instruction 'smlsld'.
kIdSmlsldx, //!< Instruction 'smlsldx'.
kIdSmmla, //!< Instruction 'smmla'.
kIdSmmlar, //!< Instruction 'smmlar'.
kIdSmmls, //!< Instruction 'smmls'.
kIdSmmlsr, //!< Instruction 'smmlsr'.
kIdSmmul, //!< Instruction 'smmul'.
kIdSmmulr, //!< Instruction 'smmulr'.
kIdSmuad, //!< Instruction 'smuad'.
kIdSmuadx, //!< Instruction 'smuadx'.
kIdSmulbb, //!< Instruction 'smulbb'.
kIdSmulbt, //!< Instruction 'smulbt'.
kIdSmull, //!< Instruction 'smull'.
kIdSmulls, //!< Instruction 'smulls' (ARM).
kIdSmultb, //!< Instruction 'smultb'.
kIdSmultt, //!< Instruction 'smultt'.
kIdSmulwb, //!< Instruction 'smulwb'.
kIdSmulwt, //!< Instruction 'smulwt'.
kIdSmusd, //!< Instruction 'smusd'.
kIdSmusdx, //!< Instruction 'smusdx'.
kIdSrsda, //!< Instruction 'srsda' (ARM).
kIdSrsdb, //!< Instruction 'srsdb' (ARM).
kIdSrsia, //!< Instruction 'srsia' (ARM).
kIdSrsib, //!< Instruction 'srsib' (ARM).
kIdSsat, //!< Instruction 'ssat'.
kIdSsat16, //!< Instruction 'ssat16'.
kIdSsax, //!< Instruction 'ssax'.
kIdSsbb, //!< Instruction 'ssbb'.
kIdSsub16, //!< Instruction 'ssub16'.
kIdSsub8, //!< Instruction 'ssub8'.
kIdStl, //!< Instruction 'stl'.
kIdStlb, //!< Instruction 'stlb'.
kIdStlex, //!< Instruction 'stlex'.
kIdStlexb, //!< Instruction 'stlexb'.
kIdStlexd, //!< Instruction 'stlexd'.
kIdStlexh, //!< Instruction 'stlexh'.
kIdStlh, //!< Instruction 'stlh'.
kIdStmda, //!< Instruction 'stmda' (ARM).
kIdStmdb, //!< Instruction 'stmdb'.
kIdStmia, //!< Instruction 'stmia'.
kIdStmib, //!< Instruction 'stmib' (ARM).
kIdStr, //!< Instruction 'str'.
kIdStrb, //!< Instruction 'strb'.
kIdStrbt, //!< Instruction 'strbt'.
kIdStrd, //!< Instruction 'strd'.
kIdStrex, //!< Instruction 'strex'.
kIdStrexb, //!< Instruction 'strexb'.
kIdStrexd, //!< Instruction 'strexd'.
kIdStrexh, //!< Instruction 'strexh'.
kIdStrh, //!< Instruction 'strh'.
kIdStrht, //!< Instruction 'strht'.
kIdStrt, //!< Instruction 'strt'.
kIdSub, //!< Instruction 'sub'.
kIdSubs, //!< Instruction 'subs'.
kIdSvc, //!< Instruction 'svc'.
kIdSxtab, //!< Instruction 'sxtab'.
kIdSxtab16, //!< Instruction 'sxtab16'.
kIdSxtah, //!< Instruction 'sxtah'.
kIdSxtb, //!< Instruction 'sxtb'.
kIdSxtb16, //!< Instruction 'sxtb16'.
kIdSxth, //!< Instruction 'sxth'.
kIdTbb, //!< Instruction 'tbb' (THUMB).
kIdTbh, //!< Instruction 'tbh' (THUMB).
kIdTeq, //!< Instruction 'teq'.
kIdTst, //!< Instruction 'tst'.
kIdUadd16, //!< Instruction 'uadd16'.
kIdUadd8, //!< Instruction 'uadd8'.
kIdUasx, //!< Instruction 'uasx'.
kIdUbfx, //!< Instruction 'ubfx'.
kIdUdf, //!< Instruction 'udf' (ARM).
kIdUdiv, //!< Instruction 'udiv' {IDIVA & IDIVT}.
kIdUhadd16, //!< Instruction 'uhadd16'.
kIdUhadd8, //!< Instruction 'uhadd8'.
kIdUhasx, //!< Instruction 'uhasx'.
kIdUhsax, //!< Instruction 'uhsax'.
kIdUhsub16, //!< Instruction 'uhsub16'.
kIdUhsub8, //!< Instruction 'uhsub8'.
kIdUmaal, //!< Instruction 'umaal'.
kIdUmlal, //!< Instruction 'umlal'.
kIdUmlals, //!< Instruction 'umlals' (ARM).
kIdUmull, //!< Instruction 'umull'.
kIdUmulls, //!< Instruction 'umulls' (ARM).
kIdUqadd16, //!< Instruction 'uqadd16'.
kIdUqadd8, //!< Instruction 'uqadd8'.
kIdUqasx, //!< Instruction 'uqasx'.
kIdUqsax, //!< Instruction 'uqsax'.
kIdUqsub16, //!< Instruction 'uqsub16'.
kIdUqsub8, //!< Instruction 'uqsub8'.
kIdUsad8, //!< Instruction 'usad8'.
kIdUsada8, //!< Instruction 'usada8'.
kIdUsat, //!< Instruction 'usat'.
kIdUsat16, //!< Instruction 'usat16'.
kIdUsax, //!< Instruction 'usax'.
kIdUsub16, //!< Instruction 'usub16'.
kIdUsub8, //!< Instruction 'usub8'.
kIdUxtab, //!< Instruction 'uxtab'.
kIdUxtab16, //!< Instruction 'uxtab16'.
kIdUxtah, //!< Instruction 'uxtah'.
kIdUxtb, //!< Instruction 'uxtb'.
kIdUxtb16, //!< Instruction 'uxtb16'.
kIdUxth, //!< Instruction 'uxth'.
kIdVaba, //!< Instruction 'vaba' {ASIMD}.
kIdVabal, //!< Instruction 'vabal' {ASIMD}.
kIdVabd, //!< Instruction 'vabd' {ASIMD ~FP16}.
kIdVabdl, //!< Instruction 'vabdl' {ASIMD}.
kIdVabs, //!< Instruction 'vabs' {ASIMD & FP ~FP16}.
kIdVacge, //!< Instruction 'vacge' {ASIMD ~FP16}.
kIdVacgt, //!< Instruction 'vacgt' {ASIMD ~FP16}.
kIdVacle, //!< Instruction 'vacle' {ASIMD ~FP16}.
kIdVaclt, //!< Instruction 'vaclt' {ASIMD ~FP16}.
kIdVadd, //!< Instruction 'vadd' {ASIMD & FP ~FP16}.
kIdVaddhn, //!< Instruction 'vaddhn' {ASIMD}.
kIdVaddl, //!< Instruction 'vaddl' {ASIMD}.
kIdVaddw, //!< Instruction 'vaddw' {ASIMD}.
kIdVand, //!< Instruction 'vand' {ASIMD}.
kIdVbic, //!< Instruction 'vbic' {ASIMD}.
kIdVbif, //!< Instruction 'vbif' {ASIMD}.
kIdVbit, //!< Instruction 'vbit' {ASIMD}.
kIdVbsl, //!< Instruction 'vbsl' {ASIMD}.
kIdVcadd, //!< Instruction 'vcadd' {FCMA ~FP16}.
kIdVceq, //!< Instruction 'vceq' {ASIMD ~FP16}.
kIdVcge, //!< Instruction 'vcge' {ASIMD ~FP16}.
kIdVcgt, //!< Instruction 'vcgt' {ASIMD ~FP16}.
kIdVcle, //!< Instruction 'vcle' {ASIMD ~FP16}.
kIdVcls, //!< Instruction 'vcls' {ASIMD}.
kIdVclt, //!< Instruction 'vclt' {ASIMD ~FP16}.
kIdVclz, //!< Instruction 'vclz' {ASIMD}.
kIdVcmla, //!< Instruction 'vcmla' {FCMA ~FP16}.
kIdVcmp, //!< Instruction 'vcmp' {FP ~FP16}.
kIdVcmpe, //!< Instruction 'vcmpe' {FP ~FP16}.
kIdVcnt, //!< Instruction 'vcnt' {ASIMD}.
kIdVcvt, //!< Instruction 'vcvt' {ASIMD & FP & FP16CONV}.
kIdVcvta, //!< Instruction 'vcvta' {ASIMD & FP16CONV}.
kIdVcvtb, //!< Instruction 'vcvtb' {BF16 & FP16CONV}.
kIdVcvtm, //!< Instruction 'vcvtm' {ASIMD & FP16CONV}.
kIdVcvtn, //!< Instruction 'vcvtn' {ASIMD & FP16CONV}.
kIdVcvtp, //!< Instruction 'vcvtp' {ASIMD & FP16CONV}.
kIdVcvtr, //!< Instruction 'vcvtr' {FP & FP16CONV}.
kIdVcvtt, //!< Instruction 'vcvtt' {BF16 & FP16CONV}.
kIdVdiv, //!< Instruction 'vdiv' {FP ~FP16}.
kIdVdot, //!< Instruction 'vdot' {BF16}.
kIdVdup, //!< Instruction 'vdup' {ASIMD}.
kIdVeor, //!< Instruction 'veor' {ASIMD}.
kIdVext, //!< Instruction 'vext' {ASIMD}.
kIdVfma, //!< Instruction 'vfma' {ASIMD & VFPv4 ~FP16}.
kIdVfmab, //!< Instruction 'vfmab' {BF16}.
kIdVfmal, //!< Instruction 'vfmal' {FHM}.
kIdVfmat, //!< Instruction 'vfmat' {BF16}.
kIdVfms, //!< Instruction 'vfms' {ASIMD & VFPv4 ~FP16}.
kIdVfmsl, //!< Instruction 'vfmsl' {FHM}.
kIdVfnma, //!< Instruction 'vfnma' {VFPv4 ~FP16}.
kIdVfnms, //!< Instruction 'vfnms' {VFPv4 ~FP16}.
kIdVhadd, //!< Instruction 'vhadd' {ASIMD}.
kIdVhsub, //!< Instruction 'vhsub' {ASIMD}.
kIdVins, //!< Instruction 'vins' {ASIMD ~FP16}.
kIdVjcvt, //!< Instruction 'vjcvt' {JSCVT}.
kIdVld1, //!< Instruction 'vld1' {ASIMD}.
kIdVld1r, //!< Instruction 'vld1r' {ASIMD}.
kIdVld2, //!< Instruction 'vld2' {ASIMD}.
kIdVld2r, //!< Instruction 'vld2r' {ASIMD}.
kIdVld3, //!< Instruction 'vld3' {ASIMD}.
kIdVld3r, //!< Instruction 'vld3r' {ASIMD}.
kIdVld4, //!< Instruction 'vld4' {ASIMD}.
kIdVld4r, //!< Instruction 'vld4r' {ASIMD}.
kIdVldmdb, //!< Instruction 'vldmdb' {ASIMD}.
kIdVldmia, //!< Instruction 'vldmia' {ASIMD}.
kIdVldr, //!< Instruction 'vldr' {FP ~FP16}.
kIdVmax, //!< Instruction 'vmax' {ASIMD ~FP16}.
kIdVmaxnm, //!< Instruction 'vmaxnm' {ASIMD ~FP16}.
kIdVmin, //!< Instruction 'vmin' {ASIMD ~FP16}.
kIdVminnm, //!< Instruction 'vminnm' {ASIMD ~FP16}.
kIdVmla, //!< Instruction 'vmla' {ASIMD & FP ~FP16}.
kIdVmlal, //!< Instruction 'vmlal' {ASIMD}.
kIdVmls, //!< Instruction 'vmls' {ASIMD & FP ~FP16}.
kIdVmlsl, //!< Instruction 'vmlsl' {ASIMD}.
kIdVmmla, //!< Instruction 'vmmla' {BF16}.
kIdVmov, //!< Instruction 'vmov' {ASIMD & FP ~FP16}.
kIdVmovl, //!< Instruction 'vmovl' {ASIMD}.
kIdVmovn, //!< Instruction 'vmovn' {ASIMD}.
kIdVmovx, //!< Instruction 'vmovx' {FP ~FP16}.
kIdVmul, //!< Instruction 'vmul' {ASIMD & FP ~FP16}.
kIdVmull, //!< Instruction 'vmull' {ASIMD}.
kIdVmvn, //!< Instruction 'vmvn' {ASIMD}.
kIdVneg, //!< Instruction 'vneg' {ASIMD & FP ~FP16}.
kIdVnmla, //!< Instruction 'vnmla' {FP ~FP16}.
kIdVnmls, //!< Instruction 'vnmls' {FP ~FP16}.
kIdVnmul, //!< Instruction 'vnmul' {FP ~FP16}.
kIdVorn, //!< Instruction 'vorn' {ASIMD}.
kIdVorr, //!< Instruction 'vorr' {ASIMD}.
kIdVpadal, //!< Instruction 'vpadal' {ASIMD}.
kIdVpadd, //!< Instruction 'vpadd' {ASIMD ~FP16}.
kIdVpaddl, //!< Instruction 'vpaddl' {ASIMD}.
kIdVpmax, //!< Instruction 'vpmax' {ASIMD ~FP16}.
kIdVpmin, //!< Instruction 'vpmin' {ASIMD ~FP16}.
kIdVpop, //!< Instruction 'vpop' {ASIMD}.
kIdVpush, //!< Instruction 'vpush' {ASIMD}.
kIdVqabs, //!< Instruction 'vqabs' {ASIMD}.
kIdVqadd, //!< Instruction 'vqadd' {ASIMD}.
kIdVqdmlal, //!< Instruction 'vqdmlal' {ASIMD}.
kIdVqdmlsl, //!< Instruction 'vqdmlsl' {ASIMD}.
kIdVqdmulh, //!< Instruction 'vqdmulh' {ASIMD}.
kIdVqdmull, //!< Instruction 'vqdmull' {ASIMD}.
kIdVqmovn, //!< Instruction 'vqmovn' {ASIMD}.
kIdVqmovun, //!< Instruction 'vqmovun' {ASIMD}.
kIdVqneg, //!< Instruction 'vqneg' {ASIMD}.
kIdVqrdmlah, //!< Instruction 'vqrdmlah' {RDM}.
kIdVqrdmlsh, //!< Instruction 'vqrdmlsh' {RDM}.
kIdVqrdmulh, //!< Instruction 'vqrdmulh' {ASIMD}.
kIdVqrshl, //!< Instruction 'vqrshl' {ASIMD}.
kIdVqrshrn, //!< Instruction 'vqrshrn' {ASIMD}.
kIdVqrshrun, //!< Instruction 'vqrshrun' {ASIMD}.
kIdVqshl, //!< Instruction 'vqshl' {ASIMD}.
kIdVqshlu, //!< Instruction 'vqshlu' {ASIMD}.
kIdVqshrn, //!< Instruction 'vqshrn' {ASIMD}.
kIdVqshrun, //!< Instruction 'vqshrun' {ASIMD}.
kIdVqsub, //!< Instruction 'vqsub' {ASIMD}.
kIdVraddhn, //!< Instruction 'vraddhn' {ASIMD}.
kIdVrecpe, //!< Instruction 'vrecpe' {ASIMD ~FP16}.
kIdVrecps, //!< Instruction 'vrecps' {ASIMD ~FP16}.
kIdVrev16, //!< Instruction 'vrev16' {ASIMD}.
kIdVrev32, //!< Instruction 'vrev32' {ASIMD}.
kIdVrev64, //!< Instruction 'vrev64' {ASIMD}.
kIdVrhadd, //!< Instruction 'vrhadd' {ASIMD}.
kIdVrinta, //!< Instruction 'vrinta' {ASIMD ~FP16}.
kIdVrintm, //!< Instruction 'vrintm' {ASIMD ~FP16}.
kIdVrintn, //!< Instruction 'vrintn' {ASIMD ~FP16}.
kIdVrintp, //!< Instruction 'vrintp' {ASIMD ~FP16}.
kIdVrintr, //!< Instruction 'vrintr' {ASIMD ~FP16}.
kIdVrintx, //!< Instruction 'vrintx' {ASIMD ~FP16}.
kIdVrintz, //!< Instruction 'vrintz' {ASIMD ~FP16}.
kIdVrshl, //!< Instruction 'vrshl' {ASIMD}.
kIdVrshr, //!< Instruction 'vrshr' {ASIMD}.
kIdVrshrn, //!< Instruction 'vrshrn' {ASIMD}.
kIdVrsqrte, //!< Instruction 'vrsqrte' {ASIMD ~FP16}.
kIdVrsqrts, //!< Instruction 'vrsqrts' {ASIMD ~FP16}.
kIdVrsra, //!< Instruction 'vrsra' {ASIMD}.
kIdVrsubhn, //!< Instruction 'vrsubhn' {ASIMD}.
kIdVsdot, //!< Instruction 'vsdot' {DOTPROD}.
kIdVseleq, //!< Instruction 'vseleq' {ASIMD ~FP16}.
kIdVselge, //!< Instruction 'vselge' {ASIMD ~FP16}.
kIdVselgt, //!< Instruction 'vselgt' {ASIMD ~FP16}.
kIdVselvs, //!< Instruction 'vselvs' {ASIMD ~FP16}.
kIdVshl, //!< Instruction 'vshl' {ASIMD}.
kIdVshll, //!< Instruction 'vshll' {ASIMD}.
kIdVshr, //!< Instruction 'vshr' {ASIMD}.
kIdVshrn, //!< Instruction 'vshrn' {ASIMD}.
kIdVsli, //!< Instruction 'vsli' {ASIMD}.
kIdVsmmla, //!< Instruction 'vsmmla' {I8MM}.
kIdVsqrt, //!< Instruction 'vsqrt' {FP ~FP16}.
kIdVsra, //!< Instruction 'vsra' {ASIMD}.
kIdVsri, //!< Instruction 'vsri' {ASIMD}.
kIdVst1, //!< Instruction 'vst1' {ASIMD}.
kIdVst2, //!< Instruction 'vst2' {ASIMD}.
kIdVst3, //!< Instruction 'vst3' {ASIMD}.
kIdVst4, //!< Instruction 'vst4' {ASIMD}.
kIdVstmdb, //!< Instruction 'vstmdb' {ASIMD}.
kIdVstmia, //!< Instruction 'vstmia' {ASIMD}.
kIdVstr, //!< Instruction 'vstr' {FP ~FP16}.
kIdVsub, //!< Instruction 'vsub' {ASIMD & FP ~FP16}.
kIdVsubhn, //!< Instruction 'vsubhn' {ASIMD}.
kIdVsubl, //!< Instruction 'vsubl' {ASIMD}.
kIdVsubw, //!< Instruction 'vsubw' {ASIMD}.
kIdVsudot, //!< Instruction 'vsudot' {I8MM}.
kIdVswp, //!< Instruction 'vswp' {ASIMD}.
kIdVtbl, //!< Instruction 'vtbl' {ASIMD}.
kIdVtbx, //!< Instruction 'vtbx' {ASIMD}.
kIdVtrn, //!< Instruction 'vtrn' {ASIMD}.
kIdVtst, //!< Instruction 'vtst' {ASIMD}.
kIdVudot, //!< Instruction 'vudot' {DOTPROD}.
kIdVummla, //!< Instruction 'vummla' {I8MM}.
kIdVusdot, //!< Instruction 'vusdot' {I8MM}.
kIdVusmmla, //!< Instruction 'vusmmla' {I8MM}.
kIdVuzp, //!< Instruction 'vuzp' {ASIMD}.
kIdVzip, //!< Instruction 'vzip' {ASIMD}.
kIdWfe, //!< Instruction 'wfe'.
kIdWfi, //!< Instruction 'wfi'.
kIdYield, //!< Instruction 'yield'.
_kIdCount
// ----------------------------------------------------------------------------
// ${a32::InstId:End}
};
//! Tests whether the `inst_id` is defined (counts also Inst::kIdNone, which must be zero).
//!
//! \note This function required identifier to be without modifiers. If the given instruction id contains modifiers
//! it would return false as modifiers overflow `_kIdCount`.
static constexpr inline bool is_defined_id(InstId inst_id) noexcept {
return inst_id < _kIdCount;
}
};
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32GLOBALS_H_INCLUDED

223
asmjit/arm/a32instapi.cpp Normal file
View File

@@ -0,0 +1,223 @@
// 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 <asmjit/core/api-build_p.h>
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/support/support_p.h>
#include <asmjit/arm/a32instapi_p.h>
#include <asmjit/arm/a32instdb_p.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
namespace InstInternal {
// a32::InstAPI - Text
// ===================
#ifndef ASMJIT_NO_TEXT
Error inst_id_to_string(InstId inst_id, InstStringifyOptions options, String& output) noexcept {
uint32_t real_id = inst_id & uint32_t(InstIdParts::kRealId);
if (ASMJIT_UNLIKELY(!Inst::is_defined_id(real_id)))
return make_error(Error::kInvalidInstruction);
return InstNameUtils::decode(InstDB::_inst_name_index_table[real_id], options, InstDB::_inst_name_string_table, output);
}
InstId string_to_inst_id(const char* s, size_t len) noexcept {
return InstNameUtils::find_instruction(s, len, InstDB::_inst_name_index_table, InstDB::_inst_name_string_table, InstDB::inst_name_index);
}
#endif // !ASMJIT_NO_TEXT
// a32::InstAPI - Validation
// =========================
#ifndef ASMJIT_NO_VALIDATION
Error validate(const BaseInst& inst, const Operand_* operands, size_t op_count, ValidationFlags validation_flags) noexcept {
// TODO: AArch32 tooling.
Support::maybe_unused(inst, operands, op_count, validation_flags);
return kErrorOk;
}
#endif // !ASMJIT_NO_VALIDATION
// a32::InstAPI - Introspection
// ============================
#ifndef ASMJIT_NO_INTROSPECTION
struct InstRWInfoRecord {
//! RWX information for each operand.
uint8_t rwx[Globals::kMaxOpCount];
//! Index to InstRWFlagsRecord table.
uint8_t rw_flags_index;
};
struct InstRWFlagsRecord {
//! Read flags.
CpuRWFlags r;
//! Written flags.
CpuRWFlags w;
};
// ${a32::RWInfo:Begin}
// ------------------- Automatically generated, do not edit -------------------
static const constexpr InstRWInfoRecord inst_rw_info_data[] = {
#define R uint8_t(OpRWFlags::kRead)
#define W uint8_t(OpRWFlags::kWrite)
#define X uint8_t(OpRWFlags::kRW)
{{ R, R, R, R, R, R }, 0}, // #0 [ref=105x]
{{ W, R, R, R, R, R }, 1}, // #1 [ref=3x]
{{ W, R, R, R, R, R }, 2}, // #2 [ref=1x]
{{ W, R, R, R, R, R }, 0}, // #3 [ref=243x]
{{ W, R, R, R, R, R }, 3}, // #4 [ref=5x]
{{ X, R, R, R, R, R }, 0}, // #5 [ref=32x]
{{ W, R, R, R, R, R }, 4}, // #6 [ref=11x]
{{ R, R, R, R, R, R }, 3}, // #7 [ref=2x]
{{ W, W, R, R, R, R }, 0}, // #8 [ref=6x]
{{ W, R, R, R, R, R }, 5}, // #9 [ref=2x]
{{ R, R, W, R, R, R }, 0}, // #10 [ref=2x]
{{ R, R, W, W, R, R }, 0}, // #11 [ref=2x]
{{ W, R, R, R, R, R }, 6}, // #12 [ref=20x]
{{ W, R, R, R, R, R }, 7}, // #13 [ref=12x]
{{ W, R, R, R, R, R }, 8}, // #14 [ref=1x]
{{ X, X, R, R, R, R }, 0}, // #15 [ref=13x]
{{ X, X, R, R, R, R }, 5}, // #16 [ref=2x]
{{ X, X, R, R, R, R }, 6}, // #17 [ref=2x]
{{ W, W, R, R, R, R }, 5}, // #18 [ref=2x]
{{ R, R, R, R, R, R }, 4}, // #19 [ref=2x]
{{ W, W, W, R, R, R }, 0}, // #20 [ref=2x]
{{ W, W, W, W, R, R }, 0} // #21 [ref=2x]
#undef R
#undef W
#undef X
};
static const constexpr InstRWFlagsRecord instRWFlagsData[] = {
{ CpuRWFlags::kNone, CpuRWFlags::kNone }, // #0 [ref=407x]
{ CpuRWFlags::kARM_C, CpuRWFlags::kNone }, // #1 [ref=3x]
{ CpuRWFlags::kARM_C, CpuRWFlags::kARM_C | CpuRWFlags::kARM_N | CpuRWFlags::kARM_V | CpuRWFlags::kARM_Z }, // #2 [ref=1x]
{ CpuRWFlags::kNone, CpuRWFlags::kARM_C | CpuRWFlags::kARM_N | CpuRWFlags::kARM_V | CpuRWFlags::kARM_Z }, // #3 [ref=7x]
{ CpuRWFlags::kNone, CpuRWFlags::kARM_C | CpuRWFlags::kARM_N | CpuRWFlags::kARM_Z }, // #4 [ref=13x]
{ CpuRWFlags::kNone, CpuRWFlags::kARM_N | CpuRWFlags::kARM_Z }, // #5 [ref=6x]
{ CpuRWFlags::kARM_Q, CpuRWFlags::kARM_Q }, // #6 [ref=22x]
{ CpuRWFlags::kNone, CpuRWFlags::kARM_GE }, // #7 [ref=12x]
{ CpuRWFlags::kARM_GE, CpuRWFlags::kNone } // #8 [ref=1x]
};
static const constexpr uint8_t instRWInfoIndex[] {
0, 1, 2, 3, 4, 3, 5, 5, 3, 3, 3, 6, 3, 6, 0, 3, 3, 3, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 7, 7, 0, 0, 0, 3, 3, 3, 3, 3, 3,
0, 0, 0, 0, 0, 0, 0, 3, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 8, 3, 3, 0, 0, 0, 0,
3, 3, 3, 8, 3, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 6, 0, 0, 0, 0, 3, 9, 3, 0xFFu, 0xFFu, 5, 3, 10, 10, 11, 11, 3, 0,
3, 9, 3, 6, 0, 3, 6, 3, 6, 3, 3, 0, 0, 0, 0xFFu, 0, 0, 12, 3, 3, 3, 12, 12, 3, 12, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, 6,
1, 6, 3, 4, 3, 4, 13, 13, 13, 0, 1, 4, 3, 3, 14, 0, 0, 0, 0, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 0, 12, 12,
12, 12, 15, 15, 15, 15, 15, 16, 15, 15, 12, 12, 12, 12, 12, 12, 17, 17, 3, 3, 3, 3, 3, 3, 12, 12, 3, 3, 8, 18, 3, 3, 3,
3, 3, 3, 0, 0, 0, 0, 12, 12, 13, 0, 13, 13, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 3, 4, 0,
3, 3, 3, 3, 3, 3, 0, 0, 19, 19, 13, 13, 13, 3, 0, 3, 3, 3, 3, 3, 3, 3, 15, 15, 16, 8, 18, 3, 3, 3, 3, 3, 3, 3, 3, 12,
12, 13, 13, 13, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0xFFu, 0xFFu, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
5, 0, 0, 3, 0xFFu, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 5, 3, 5, 5, 5, 5, 3, 3, 3, 3, 0xFFu, 0xFFu, 0xFFu, 8, 20,
20, 21, 21, 0, 0, 3, 3, 3, 3, 3, 5, 5, 5, 5, 3, 0xFFu, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 0xFFu, 0xFFu, 5, 3, 3, 3, 3, 0, 0,
3, 3, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 5, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 15, 3, 3, 15, 3, 3, 3, 3, 3, 15, 15, 0,
0, 0
};
// ----------------------------------------------------------------------------
// ${a32::RWInfo:End}
Error query_rw_info(const BaseInst& inst, const Operand_* operands, size_t op_count, InstRWInfo* out) noexcept {
uint32_t inst_id = inst.inst_id();
uint32_t real_id = inst_id & uint32_t(InstIdParts::kRealId);
if (ASMJIT_UNLIKELY(!Inst::is_defined_id(real_id)))
return make_error(Error::kInvalidInstruction);
out->_inst_flags = InstRWFlags::kNone;
out->_op_count = uint8_t(op_count);
out->_rm_feature = 0;
out->_extra_reg.reset();
out->_read_flags = CpuRWFlags::kNone;
out->_write_flags = CpuRWFlags::kNone;
size_t index = instRWInfoIndex[real_id];
if (index < 0xFFu) {
const InstRWInfoRecord& rwInfo = inst_rw_info_data[index];
size_t rw_flags_index = rwInfo.rw_flags_index;
out->_read_flags = instRWFlagsData[rw_flags_index].r;
out->_write_flags = instRWFlagsData[rw_flags_index].w;
for (size_t i = 0; i < op_count; i++) {
uint32_t access = rwInfo.rwx[i];
OpRWInfo& rwOp = out->_operands[i];
const Operand_& srcOp = operands[i];
if (!srcOp.is_reg_or_reg_list_or_mem()) {
rwOp.reset();
continue;
}
rwOp._op_flags = OpRWFlags(access);
rwOp._phys_id = Reg::kIdBad;
rwOp._rm_size = 0;
rwOp._reset_reserved();
uint64_t r_byte_mask = rwOp.is_read() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
uint64_t w_byte_mask = rwOp.is_write() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
rwOp._read_byte_mask = r_byte_mask;
rwOp._write_byte_mask = w_byte_mask;
rwOp._extend_byte_mask = 0;
rwOp._consecutive_lead_count = 0;
if (srcOp.is_mem()) {
const Mem& mem_op = srcOp.as<Mem>();
if (mem_op.has_base()) {
rwOp.add_op_flags(OpRWFlags::kMemBaseRead);
}
if (mem_op.has_index()) {
rwOp.add_op_flags(mem_op.is_pre_or_post() ? OpRWFlags::kMemIndexRW : OpRWFlags::kMemIndexRead);
}
}
else if (srcOp.as<Vec>().has_element_index()) {
// Only part of the vector is accessed if element index [] is used.
uint32_t elementSize = data_type_size(inst.arm_dt());
uint32_t element_index = srcOp.as<Vec>().element_index();
// NOTE: DataType must be present otherwise it's impossible to calculate the access flags.
if (!elementSize)
return make_error(Error::kInvalidInstruction);
uint64_t accessMask = uint64_t(Support::lsb_mask<uint32_t>(elementSize)) << (element_index * elementSize);
rwOp._read_byte_mask &= accessMask;
rwOp._write_byte_mask &= accessMask;
}
}
return kErrorOk;
}
else {
// TODO: [ARM] Not finished introspection.
return make_error(Error::kInvalidState);
}
}
Error query_features(const BaseInst& inst, const Operand_* operands, size_t op_count, CpuFeatures* out) noexcept {
// TODO: AArch32 tooling.
Support::maybe_unused(inst, operands, op_count, out);
return kErrorOk;
}
#endif // !ASMJIT_NO_INTROSPECTION
} // {InstInternal}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH32

42
asmjit/arm/a32instapi_p.h Normal file
View File

@@ -0,0 +1,42 @@
// 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_ARM_A32INSTAPI_H_P_INCLUDED
#define ASMJIT_ARM_A32INSTAPI_H_P_INCLUDED
#include <asmjit/core/codeholder.h>
#include <asmjit/arm/a32instdb_p.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \cond INTERNAL
//! \addtogroup asmjit_a32
//! \{
namespace InstInternal {
#ifndef ASMJIT_NO_TEXT
Error ASMJIT_CDECL inst_id_to_string(InstId inst_id, InstStringifyOptions options, String& output) noexcept;
InstId ASMJIT_CDECL string_to_inst_id(const char* s, size_t len) noexcept;
#endif // !ASMJIT_NO_TEXT
#ifndef ASMJIT_NO_VALIDATION
Error ASMJIT_CDECL validate(const BaseInst& inst, const Operand_* operands, size_t op_count, ValidationFlags validation_flags) noexcept;
#endif // !ASMJIT_NO_VALIDATION
#ifndef ASMJIT_NO_INTROSPECTION
Error ASMJIT_CDECL query_rw_info(const BaseInst& inst, const Operand_* operands, size_t op_count, InstRWInfo* out) noexcept;
Error ASMJIT_CDECL query_features(const BaseInst& inst, const Operand_* operands, size_t op_count, CpuFeatures* out) noexcept;
#endif // !ASMJIT_NO_INTROSPECTION
} // {InstInternal}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32INSTAPI_H_P_INCLUDED

547
asmjit/arm/a32instdb.cpp Normal file
View File

@@ -0,0 +1,547 @@
// 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 <asmjit/core/api-build_p.h>
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/arm/a32instdb_p.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
// a32::InstDB - Id <-> Name
// =========================
#ifndef ASMJIT_NO_TEXT
// ${a32::NameData:Begin}
// ------------------- Automatically generated, do not edit -------------------
const InstNameIndex InstDB::inst_name_index = {{
{ Inst::kIdAdc , Inst::kIdAsrs + 1 },
{ Inst::kIdB , Inst::kIdBxj + 1 },
{ Inst::kIdCbnz , Inst::kIdCsdb + 1 },
{ Inst::kIdDbg , Inst::kIdDsb + 1 },
{ Inst::kIdEor , Inst::kIdEsb + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 },
{ Inst::kIdHlt , Inst::kIdHvc + 1 },
{ Inst::kIdIsb , Inst::kIdItttt + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 },
{ Inst::kIdLda , Inst::kIdLsrs + 1 },
{ Inst::kIdMcr , Inst::kIdMvns + 1 },
{ Inst::kIdNop , Inst::kIdNop + 1 },
{ Inst::kIdOrn , Inst::kIdOrrs + 1 },
{ Inst::kIdPkhbt , Inst::kIdPush + 1 },
{ Inst::kIdQadd , Inst::kIdQsub8 + 1 },
{ Inst::kIdRbit , Inst::kIdRscs + 1 },
{ Inst::kIdSadd16 , Inst::kIdSxth + 1 },
{ Inst::kIdTbb , Inst::kIdTst + 1 },
{ Inst::kIdUadd16 , Inst::kIdUxth + 1 },
{ Inst::kIdVaba , Inst::kIdVzip + 1 },
{ Inst::kIdWfe , Inst::kIdWfi + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 },
{ Inst::kIdYield , Inst::kIdYield + 1 },
{ Inst::kIdNone , Inst::kIdNone + 1 }
}, uint16_t(9)};
const char InstDB::_inst_name_string_table[] =
"sha256su01h2vqrdmlaulhvqrshruncrc32cbwsha1sha1sushadd1shsub1smlalbtdxtbttsmlslsx"
"tab1uhadd1uhsub1uqadd1uqsub1uxtab1vqdvqdmvqdmulvqmovvraddhvrsqrtevrsubhvusmsadd1"
"8ssat1ssub1sxtb1uadd1usadausat1usub1uxtb1vrev164";
const uint32_t InstDB::_inst_name_index_table[] = {
0x80000000, // Small ''.
0x80000C81, // Small 'adc'.
0x80098C81, // Small 'adcs'.
0x80001081, // Small 'add'.
0x80099081, // Small 'adds'.
0x80004881, // Small 'adr'.
0x80024CA1, // Small 'aesd'.
0x8002CCA1, // Small 'aese'.
0x86D4CCA1, // Small 'aesimc'.
0x8036CCA1, // Small 'aesmc'.
0x800011C1, // Small 'and'.
0x800991C1, // Small 'ands'.
0x80004A61, // Small 'asr'.
0x8009CA61, // Small 'asrs'.
0x80000002, // Small 'b'.
0x80000CC2, // Small 'bfc'.
0x800024C2, // Small 'bfi'.
0x80000D22, // Small 'bic'.
0x80098D22, // Small 'bics'.
0x800A4162, // Small 'bkpt'.
0x80000182, // Small 'bl'.
0x80006182, // Small 'blx'.
0x80000302, // Small 'bx'.
0x80002B02, // Small 'bxj'.
0x800D3843, // Small 'cbnz'.
0x80006843, // Small 'cbz'.
0x84814983, // Small 'clrbhb'.
0x8182C983, // Small 'clrex'.
0x80006983, // Small 'clz'.
0x800039A3, // Small 'cmn'.
0x800041A3, // Small 'cmp'.
0x80004E03, // Small 'cps'.
0x8044CE03, // Small 'cpsid'.
0x8054CE03, // Small 'cpsie'.
0x85DF0E43, // Small 'crc32b'.
0x0000701E, // Large 'crc32cb'.
0x1001601E, // Large 'crc32c|h'.
0x1025601E, // Large 'crc32c|w'.
0x91DF0E43, // Small 'crc32h'.
0xAFDF0E43, // Small 'crc32w'.
0x80011263, // Small 'csdb'.
0x80001C44, // Small 'dbg'.
0x81C9C064, // Small 'dcps1'.
0x81D9C064, // Small 'dcps2'.
0x81E9C064, // Small 'dcps3'.
0x800009A4, // Small 'dmb'.
0x80000A64, // Small 'dsb'.
0x800049E5, // Small 'eor'.
0x8009C9E5, // Small 'eors'.
0x800A1645, // Small 'eret'.
0x80000A65, // Small 'esb'.
0x80005188, // Small 'hlt'.
0x80000EC8, // Small 'hvc'.
0x80000A69, // Small 'isb'.
0x80000289, // Small 'it'.
0x80001689, // Small 'ite'.
0x80029689, // Small 'itee'.
0x80529689, // Small 'iteee'.
0x81429689, // Small 'iteet'.
0x800A1689, // Small 'itet'.
0x805A1689, // Small 'itete'.
0x814A1689, // Small 'itett'.
0x80005289, // Small 'itt'.
0x8002D289, // Small 'itte'.
0x8052D289, // Small 'ittee'.
0x8142D289, // Small 'ittet'.
0x800A5289, // Small 'ittt'.
0x805A5289, // Small 'ittte'.
0x814A5289, // Small 'itttt'.
0x8000048C, // Small 'lda'.
0x8001048C, // Small 'ldab'.
0x8182848C, // Small 'ldaex'.
0x8582848C, // Small 'ldaexb'.
0x8982848C, // Small 'ldaexd'.
0x9182848C, // Small 'ldaexh'.
0x8004048C, // Small 'ldah'.
0x8012348C, // Small 'ldmda'.
0x8022348C, // Small 'ldmdb'.
0x8014B48C, // Small 'ldmia'.
0x8024B48C, // Small 'ldmib'.
0x8000488C, // Small 'ldr'.
0x8001488C, // Small 'ldrb'.
0x8141488C, // Small 'ldrbt'.
0x8002488C, // Small 'ldrd'.
0x8182C88C, // Small 'ldrex'.
0x8582C88C, // Small 'ldrexb'.
0x8982C88C, // Small 'ldrexd'.
0x9182C88C, // Small 'ldrexh'.
0x8004488C, // Small 'ldrh'.
0x8144488C, // Small 'ldrht'.
0x8029C88C, // Small 'ldrsb'.
0xA829C88C, // Small 'ldrsbt'.
0x8089C88C, // Small 'ldrsh'.
0xA889C88C, // Small 'ldrsht'.
0x800A488C, // Small 'ldrt'.
0x8000326C, // Small 'lsl'.
0x8009B26C, // Small 'lsls'.
0x80004A6C, // Small 'lsr'.
0x8009CA6C, // Small 'lsrs'.
0x8000486D, // Small 'mcr'.
0x800EC86D, // Small 'mcr2'.
0x8009486D, // Small 'mcrr'.
0x81D9486D, // Small 'mcrr2'.
0x8000058D, // Small 'mla'.
0x8009858D, // Small 'mlas'.
0x80004D8D, // Small 'mls'.
0x800059ED, // Small 'mov'.
0x8009D9ED, // Small 'movs'.
0x800A59ED, // Small 'movt'.
0x800BD9ED, // Small 'movw'.
0x80000E4D, // Small 'mrc'.
0x800E8E4D, // Small 'mrc2'.
0x8001CA4D, // Small 'mrrc'.
0x81D1CA4D, // Small 'mrrc2'.
0x80004E4D, // Small 'mrs'.
0x80004A6D, // Small 'msr'.
0x800032AD, // Small 'mul'.
0x8009B2AD, // Small 'muls'.
0x80003ACD, // Small 'mvn'.
0x8009BACD, // Small 'mvns'.
0x800041EE, // Small 'nop'.
0x80003A4F, // Small 'orn'.
0x8009BA4F, // Small 'orns'.
0x80004A4F, // Small 'orr'.
0x8009CA4F, // Small 'orrs'.
0x81412170, // Small 'pkhbt'.
0x802A2170, // Small 'pkhtb'.
0x80001190, // Small 'pld'.
0x800B9190, // Small 'pldw'.
0x80002590, // Small 'pli'.
0x800041F0, // Small 'pop'.
0x80214E70, // Small 'pssbb'.
0x80044EB0, // Small 'push'.
0x80021031, // Small 'qadd'.
0x10055061, // Large 'qadd1|6'.
0x10A04061, // Large 'qadd|8'.
0x800C4C31, // Small 'qasx'.
0x80420491, // Small 'qdadd'.
0x802ACC91, // Small 'qdsub'.
0x800C0671, // Small 'qsax'.
0x80015671, // Small 'qsub'.
0x10055067, // Large 'qsub1|6'.
0x10A04067, // Large 'qsub|8'.
0x800A2452, // Small 'rbit'.
0x800058B2, // Small 'rev'.
0x000050CA, // Large 'rev16'.
0x8089D8B2, // Small 'revsh'.
0x801214D2, // Small 'rfeda'.
0x802214D2, // Small 'rfedb'.
0x801494D2, // Small 'rfeia'.
0x802494D2, // Small 'rfeib'.
0x800049F2, // Small 'ror'.
0x8009C9F2, // Small 'rors'.
0x80006252, // Small 'rrx'.
0x8009E252, // Small 'rrxs'.
0x80000A72, // Small 'rsb'.
0x80098A72, // Small 'rsbs'.
0x80000E72, // Small 'rsc'.
0x80098E72, // Small 'rscs'.
0x1005509B, // Large 'sadd1|6'.
0x10A0409B, // Large 'sadd|8'.
0x800C4C33, // Small 'sasx'.
0x80000053, // Small 'sb'.
0x80000C53, // Small 'sbc'.
0x80098C53, // Small 'sbcs'.
0x800C1853, // Small 'sbfx'.
0x800B2493, // Small 'sdiv'.
0x800030B3, // Small 'sel'.
0x88E2D0B3, // Small 'setend'.
0x9C1850B3, // Small 'setpan'.
0x800058B3, // Small 'sev'.
0x800658B3, // Small 'sevl'.
0x803E0513, // Small 'sha1c'.
0x808E0513, // Small 'sha1h'.
0x80DE0513, // Small 'sha1m'.
0x810E0513, // Small 'sha1p'.
0x30064026, // Large 'sha1|su0'.
0x1009602A, // Large 'sha1su|1'.
0x10016000, // Large 'sha256|h'.
0x200A6000, // Large 'sha256|h2'.
0x00009000, // Large 'sha256su0'.
0x10098000, // Large 'sha256su|1'.
0x10056030, // Large 'shadd1|6'.
0x10A05030, // Large 'shadd|8'.
0x81898513, // Small 'shasx'.
0x8180CD13, // Small 'shsax'.
0x10056036, // Large 'shsub1|6'.
0x10A05036, // Large 'shsub|8'.
0x80000DB3, // Small 'smc'.
0x8420B1B3, // Small 'smlabb'.
0xA820B1B3, // Small 'smlabt'.
0x8040B1B3, // Small 'smlad'.
0xB040B1B3, // Small 'smladx'.
0x80C0B1B3, // Small 'smlal'.
0x1024603C, // Large 'smlalb|b'.
0x1042603C, // Large 'smlalb|t'.
0x88C0B1B3, // Small 'smlald'.
0x2043503C, // Large 'smlal|dx'.
0xA6C0B1B3, // Small 'smlals'.
0x2045503C, // Large 'smlal|tb'.
0x2047503C, // Large 'smlal|tt'.
0x8540B1B3, // Small 'smlatb'.
0xA940B1B3, // Small 'smlatt'.
0x8570B1B3, // Small 'smlawb'.
0xA970B1B3, // Small 'smlawt'.
0x8049B1B3, // Small 'smlsd'.
0xB049B1B3, // Small 'smlsdx'.
0x88C9B1B3, // Small 'smlsld'.
0x20435049, // Large 'smlsl|dx'.
0x801635B3, // Small 'smmla'.
0xA41635B3, // Small 'smmlar'.
0x813635B3, // Small 'smmls'.
0xA53635B3, // Small 'smmlsr'.
0x80CAB5B3, // Small 'smmul'.
0xA4CAB5B3, // Small 'smmulr'.
0x8040D5B3, // Small 'smuad'.
0xB040D5B3, // Small 'smuadx'.
0x842655B3, // Small 'smulbb'.
0xA82655B3, // Small 'smulbt'.
0x80C655B3, // Small 'smull'.
0xA6C655B3, // Small 'smulls'.
0x854655B3, // Small 'smultb'.
0xA94655B3, // Small 'smultt'.
0x857655B3, // Small 'smulwb'.
0xA97655B3, // Small 'smulwt'.
0x8049D5B3, // Small 'smusd'.
0xB049D5B3, // Small 'smusdx'.
0x80124E53, // Small 'srsda'.
0x80224E53, // Small 'srsdb'.
0x8014CE53, // Small 'srsia'.
0x8024CE53, // Small 'srsib'.
0x800A0673, // Small 'ssat'.
0x100550A1, // Large 'ssat1|6'.
0x800C0673, // Small 'ssax'.
0x80010A73, // Small 'ssbb'.
0x100550A6, // Large 'ssub1|6'.
0x10A040A6, // Large 'ssub|8'.
0x80003293, // Small 'stl'.
0x80013293, // Small 'stlb'.
0x8182B293, // Small 'stlex'.
0x8582B293, // Small 'stlexb'.
0x8982B293, // Small 'stlexd'.
0x9182B293, // Small 'stlexh'.
0x80043293, // Small 'stlh'.
0x80123693, // Small 'stmda'.
0x80223693, // Small 'stmdb'.
0x8014B693, // Small 'stmia'.
0x8024B693, // Small 'stmib'.
0x80004A93, // Small 'str'.
0x80014A93, // Small 'strb'.
0x81414A93, // Small 'strbt'.
0x80024A93, // Small 'strd'.
0x8182CA93, // Small 'strex'.
0x8582CA93, // Small 'strexb'.
0x8982CA93, // Small 'strexd'.
0x9182CA93, // Small 'strexh'.
0x80044A93, // Small 'strh'.
0x81444A93, // Small 'strht'.
0x800A4A93, // Small 'strt'.
0x80000AB3, // Small 'sub'.
0x80098AB3, // Small 'subs'.
0x80000ED3, // Small 'svc'.
0x8020D313, // Small 'sxtab'.
0x1005604E, // Large 'sxtab1|6'.
0x8080D313, // Small 'sxtah'.
0x80015313, // Small 'sxtb'.
0x100550AB, // Large 'sxtb1|6'.
0x80045313, // Small 'sxth'.
0x80000854, // Small 'tbb'.
0x80002054, // Small 'tbh'.
0x800044B4, // Small 'teq'.
0x80005274, // Small 'tst'.
0x100550B0, // Large 'uadd1|6'.
0x10A040B0, // Large 'uadd|8'.
0x800C4C35, // Small 'uasx'.
0x800C1855, // Small 'ubfx'.
0x80001895, // Small 'udf'.
0x800B2495, // Small 'udiv'.
0x10056054, // Large 'uhadd1|6'.
0x10A05054, // Large 'uhadd|8'.
0x81898515, // Small 'uhasx'.
0x8180CD15, // Small 'uhsax'.
0x1005605A, // Large 'uhsub1|6'.
0x10A0505A, // Large 'uhsub|8'.
0x80C085B5, // Small 'umaal'.
0x80C0B1B5, // Small 'umlal'.
0xA6C0B1B5, // Small 'umlals'.
0x80C655B5, // Small 'umull'.
0xA6C655B5, // Small 'umulls'.
0x10056060, // Large 'uqadd1|6'.
0x10A05060, // Large 'uqadd|8'.
0x81898635, // Small 'uqasx'.
0x8180CE35, // Small 'uqsax'.
0x10056066, // Large 'uqsub1|6'.
0x10A05066, // Large 'uqsub|8'.
0x10A040B5, // Large 'usad|8'.
0x10A050B5, // Large 'usada|8'.
0x800A0675, // Small 'usat'.
0x100550BA, // Large 'usat1|6'.
0x800C0675, // Small 'usax'.
0x100550BF, // Large 'usub1|6'.
0x10A040BF, // Large 'usub|8'.
0x8020D315, // Small 'uxtab'.
0x1005606C, // Large 'uxtab1|6'.
0x8080D315, // Small 'uxtah'.
0x80015315, // Small 'uxtb'.
0x100550C4, // Large 'uxtb1|6'.
0x80045315, // Small 'uxth'.
0x80008836, // Small 'vaba'.
0x80C08836, // Small 'vabal'.
0x80020836, // Small 'vabd'.
0x80C20836, // Small 'vabdl'.
0x80098836, // Small 'vabs'.
0x80538C36, // Small 'vacge'.
0x81438C36, // Small 'vacgt'.
0x80560C36, // Small 'vacle'.
0x81460C36, // Small 'vaclt'.
0x80021036, // Small 'vadd'.
0x9C821036, // Small 'vaddhn'.
0x80C21036, // Small 'vaddl'.
0x81721036, // Small 'vaddw'.
0x80023836, // Small 'vand'.
0x8001A456, // Small 'vbic'.
0x80032456, // Small 'vbif'.
0x800A2456, // Small 'vbit'.
0x80064C56, // Small 'vbsl'.
0x80420476, // Small 'vcadd'.
0x80089476, // Small 'vceq'.
0x80029C76, // Small 'vcge'.
0x800A1C76, // Small 'vcgt'.
0x8002B076, // Small 'vcle'.
0x8009B076, // Small 'vcls'.
0x800A3076, // Small 'vclt'.
0x800D3076, // Small 'vclz'.
0x80163476, // Small 'vcmla'.
0x80083476, // Small 'vcmp'.
0x80583476, // Small 'vcmpe'.
0x800A3876, // Small 'vcnt'.
0x800A5876, // Small 'vcvt'.
0x801A5876, // Small 'vcvta'.
0x802A5876, // Small 'vcvtb'.
0x80DA5876, // Small 'vcvtm'.
0x80EA5876, // Small 'vcvtn'.
0x810A5876, // Small 'vcvtp'.
0x812A5876, // Small 'vcvtr'.
0x814A5876, // Small 'vcvtt'.
0x800B2496, // Small 'vdiv'.
0x800A3C96, // Small 'vdot'.
0x80085496, // Small 'vdup'.
0x80093CB6, // Small 'veor'.
0x800A60B6, // Small 'vext'.
0x8000B4D6, // Small 'vfma'.
0x8020B4D6, // Small 'vfmab'.
0x80C0B4D6, // Small 'vfmal'.
0x8140B4D6, // Small 'vfmat'.
0x8009B4D6, // Small 'vfms'.
0x80C9B4D6, // Small 'vfmsl'.
0x8016B8D6, // Small 'vfnma'.
0x8136B8D6, // Small 'vfnms'.
0x80420516, // Small 'vhadd'.
0x802ACD16, // Small 'vhsub'.
0x8009B936, // Small 'vins'.
0x814B0D56, // Small 'vjcvt'.
0x800E1196, // Small 'vld1'.
0x812E1196, // Small 'vld1r'.
0x800E9196, // Small 'vld2'.
0x812E9196, // Small 'vld2r'.
0x800F1196, // Small 'vld3'.
0x812F1196, // Small 'vld3r'.
0x800F9196, // Small 'vld4'.
0x812F9196, // Small 'vld4r'.
0x84469196, // Small 'vldmdb'.
0x82969196, // Small 'vldmia'.
0x80091196, // Small 'vldr'.
0x800C05B6, // Small 'vmax'.
0x9AEC05B6, // Small 'vmaxnm'.
0x800725B6, // Small 'vmin'.
0x9AE725B6, // Small 'vminnm'.
0x8000B1B6, // Small 'vmla'.
0x80C0B1B6, // Small 'vmlal'.
0x8009B1B6, // Small 'vmls'.
0x80C9B1B6, // Small 'vmlsl'.
0x801635B6, // Small 'vmmla'.
0x800B3DB6, // Small 'vmov'.
0x80CB3DB6, // Small 'vmovl'.
0x80EB3DB6, // Small 'vmovn'.
0x818B3DB6, // Small 'vmovx'.
0x800655B6, // Small 'vmul'.
0x80C655B6, // Small 'vmull'.
0x800759B6, // Small 'vmvn'.
0x800395D6, // Small 'vneg'.
0x801635D6, // Small 'vnmla'.
0x813635D6, // Small 'vnmls'.
0x80CAB5D6, // Small 'vnmul'.
0x800749F6, // Small 'vorn'.
0x800949F6, // Small 'vorr'.
0x98120616, // Small 'vpadal'.
0x80420616, // Small 'vpadd'.
0x98420616, // Small 'vpaddl'.
0x8180B616, // Small 'vpmax'.
0x80E4B616, // Small 'vpmin'.
0x80083E16, // Small 'vpop'.
0x8089D616, // Small 'vpush'.
0x81310636, // Small 'vqabs'.
0x80420636, // Small 'vqadd'.
0x403D3072, // Large 'vqd|mlal'.
0x404A3072, // Large 'vqd|mlsl'.
0x30134075, // Large 'vqdm|ulh'.
0x10116079, // Large 'vqdmul|l'.
0x9D67B636, // Small 'vqmovn'.
0x201C507F, // Large 'vqmov|un'.
0x8072BA36, // Small 'vqneg'.
0x1001700C, // Large 'vqrdmla|h'.
0x2000600C, // Large 'vqrdml|sh'.
0x3013500C, // Large 'vqrdm|ulh'.
0x9889CA36, // Small 'vqrshl'.
0x101D6016, // Large 'vqrshr|n'.
0x00008016, // Large 'vqrshrun'.
0x80C44E36, // Small 'vqshl'.
0xAAC44E36, // Small 'vqshlu'.
0x9D244E36, // Small 'vqshrn'.
0x5019200C, // Large 'vq|shrun'.
0x802ACE36, // Small 'vqsub'.
0x101D6084, // Large 'vraddh|n'.
0x8B019656, // Small 'vrecpe'.
0xA7019656, // Small 'vrecps'.
0x100550C9, // Large 'vrev1|6'.
0xBBEB1656, // Small 'vrev32'.
0x20CE40C9, // Large 'vrev|64'.
0x8840A256, // Small 'vrhadd'.
0x83472656, // Small 'vrinta'.
0x9B472656, // Small 'vrintm'.
0x9D472656, // Small 'vrintn'.
0xA1472656, // Small 'vrintp'.
0xA5472656, // Small 'vrintr'.
0xB1472656, // Small 'vrintx'.
0xB5472656, // Small 'vrintz'.
0x80C44E56, // Small 'vrshl'.
0x81244E56, // Small 'vrshr'.
0x9D244E56, // Small 'vrshrn'.
0x0000708A, // Large 'vrsqrte'.
0x1000608A, // Large 'vrsqrt|s'.
0x80194E56, // Small 'vrsra'.
0x101D6091, // Large 'vrsubh|n'.
0x81479276, // Small 'vsdot'.
0xA2561676, // Small 'vseleq'.
0x8A761676, // Small 'vselge'.
0xA8761676, // Small 'vselgt'.
0xA7661676, // Small 'vselvs'.
0x80062276, // Small 'vshl'.
0x80C62276, // Small 'vshll'.
0x80092276, // Small 'vshr'.
0x80E92276, // Small 'vshrn'.
0x8004B276, // Small 'vsli'.
0x82C6B676, // Small 'vsmmla'.
0x81494676, // Small 'vsqrt'.
0x8000CA76, // Small 'vsra'.
0x8004CA76, // Small 'vsri'.
0x800E5276, // Small 'vst1'.
0x800ED276, // Small 'vst2'.
0x800F5276, // Small 'vst3'.
0x800FD276, // Small 'vst4'.
0x8446D276, // Small 'vstmdb'.
0x8296D276, // Small 'vstmia'.
0x80095276, // Small 'vstr'.
0x80015676, // Small 'vsub'.
0x9C815676, // Small 'vsubhn'.
0x80C15676, // Small 'vsubl'.
0x81715676, // Small 'vsubw'.
0xA8F25676, // Small 'vsudot'.
0x80085E76, // Small 'vswp'.
0x80060A96, // Small 'vtbl'.
0x800C0A96, // Small 'vtbx'.
0x80074A96, // Small 'vtrn'.
0x800A4E96, // Small 'vtst'.
0x814792B6, // Small 'vudot'.
0x82C6B6B6, // Small 'vummla'.
0xA8F24EB6, // Small 'vusdot'.
0x30104097, // Large 'vusm|mla'.
0x80086AB6, // Small 'vuzp'.
0x80082756, // Small 'vzip'.
0x800014D7, // Small 'wfe'.
0x800024D7, // Small 'wfi'.
0x80461539 // Small 'yield'.
};
// ----------------------------------------------------------------------------
// ${a32::NameData:End}
#endif // !ASMJIT_NO_TEXT
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_AARCH32

0
asmjit/arm/a32instdb.h Normal file
View File

38
asmjit/arm/a32instdb_p.h Normal file
View File

@@ -0,0 +1,38 @@
// 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_ARM_A32INSTDB_H_P_INCLUDED
#define ASMJIT_ARM_A32INSTDB_H_P_INCLUDED
#include <asmjit/core/codeholder.h>
#include <asmjit/core/instdb_p.h>
#include <asmjit/arm/a32operand.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \cond INTERNAL
//! \addtogroup asmjit_a32
//! \{
namespace InstDB {
// a32::InstDB - Tables
// ====================
#ifndef ASMJIT_NO_TEXT
extern const InstNameIndex inst_name_index;
extern const char _inst_name_string_table[];
extern const uint32_t _inst_name_index_table[];
#endif // !ASMJIT_NO_TEXT
} // {InstDB}
//! \}
//! \endcond
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32INSTDB_H_P_INCLUDED

803
asmjit/arm/a32operand.h Normal file
View File

@@ -0,0 +1,803 @@
// 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_ARM_A32OPERAND_H_INCLUDED
#define ASMJIT_ARM_A32OPERAND_H_INCLUDED
#include <asmjit/core/operand.h>
#include <asmjit/arm/a32globals.h>
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
//! \addtogroup asmjit_a32
//! \{
//! General purpose register (AArch32).
class Gp : public UniGp {
public:
ASMJIT_DEFINE_ABSTRACT_REG(Gp, UniGp)
//! \name Constants
//! \{
//! Special register id.
enum Id : uint32_t {
//! Frame pointer register id.
kIdFP = 11u,
//! Stack register id.
kIdSP = 13u,
//! Link register id.
kIdLR = 14u,
//! Program counter register id.
kIdPC = 15u
};
//! \}
//! \name Static Constructors
//! \{
//! Creates a new 32-bit low general purpose register (R) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp make_r32(uint32_t reg_id) noexcept { return Gp(signature_of_t<RegType::kGp32>(), reg_id); }
//! Creates a new 32-bit low general purpose register (R) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp make_r(uint32_t reg_id) noexcept { return make_r32(reg_id); }
//! \}
//! \name Gp Register Accessors
//! \{
//! Test whether this register is FP register.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR bool is_fp() const noexcept { return id() == kIdFP; }
//! Test whether this register is SP register.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR bool is_sp() const noexcept { return id() == kIdSP; }
//! Test whether this register is LR register.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR bool is_lr() const noexcept { return id() == kIdLR; }
//! Test whether this register is PC register.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR bool is_pc() const noexcept { return id() == kIdPC; }
//! Returns whether the register contains a shift operation predicate
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR bool hast_shift_op() const noexcept { return predicate() != 0u; }
//! Returns shift operation predicate.
ASMJIT_INLINE_CONSTEXPR ShiftOp shift_op() const noexcept { return ShiftOp(predicate()); }
//! Sets a shift operation predicate to `op`.
ASMJIT_INLINE_CONSTEXPR void set_shift_op(ShiftOp op) noexcept { set_predicate(uint32_t(op)); }
//! Resets a shift operation predicate.
ASMJIT_INLINE_CONSTEXPR void reset_shift_op() noexcept { return reset_predicate(); }
//! \}
//! \name Clone
//! \{
//! Clones the register with assigned shift operation predicate `op`.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Gp shifted(ShiftOp op) const noexcept {
Gp r(*this);
r.set_shift_op(op);
return r;
}
//! \}
};
//! Vector register (AArch32).
class Vec : public UniVec {
public:
ASMJIT_DEFINE_ABSTRACT_REG(Vec, UniVec)
//! \cond
// Register has element index (1 bit).
// |........|........|X.......|........|
static inline constexpr uint32_t kSignatureRegElementFlagShift = 15;
static inline constexpr uint32_t kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift;
// Register element index (4 bits).
// |........|....XXXX|........|........|
static inline constexpr uint32_t kSignatureRegElementIndexShift = 16;
static inline constexpr uint32_t kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift;
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR OperandSignature _make_element_access_signature(uint32_t element_index) noexcept {
return OperandSignature{
uint32_t(RegTraits<RegType::kVec128>::kSignature) |
uint32_t(kSignatureRegElementFlagMask) |
(uint32_t(element_index << kSignatureRegElementIndexShift))
};
}
//! \endcond
//! \name Static Constructors
//! \{
//! Creates a new 32-bit vector register (S) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_v32(uint32_t reg_id) noexcept { return Vec(signature_of_t<RegType::kVec32>(), reg_id); }
//! Creates a new 64-bit vector register (D) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_v64(uint32_t reg_id) noexcept { return Vec(signature_of_t<RegType::kVec64>(), reg_id); }
//! Creates a new 128-bit vector register (Q) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_v128(uint32_t reg_id) noexcept { return Vec(signature_of_t<RegType::kVec128>(), reg_id); }
//! Creates a new 32-bit vector register (S) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_s(uint32_t reg_id) noexcept { return make_v32(reg_id); }
//! Creates a new 64-bit vector register (D) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_d(uint32_t reg_id) noexcept { return make_v64(reg_id); }
//! Creates a new 128-bit vector register (Q) having the given register id `reg_id`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_q(uint32_t reg_id) noexcept { return make_v128(reg_id); }
//! Creates a new 128-bit vector of type specified by `element_type` and `element_index`.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec make_v128_with_element_index(uint32_t element_index, uint32_t reg_id) noexcept {
return Vec(_make_element_access_signature(element_index), reg_id);
}
//! \}
//! \name Vector Register Accessors
//! \{
//! Clones and casts the register to a 32-bit S register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec v32() const noexcept { return make_v32(id()); }
//! Clones and casts the register to a 64-bit D register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec v64() const noexcept { return make_v64(id()); }
//! Clones and casts the register to a 128-bit Q register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec v128() const noexcept { return make_v128(id()); }
//! Clones and casts the register to a 32-bit S register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec s() const noexcept { return make_v32(id()); }
//! Clones and casts the register to a 64-bit D register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec d() const noexcept { return make_v64(id()); }
//! Clones and casts the register to a 128-bit Q register (element type & index is not cloned).
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec q() const noexcept { return make_v128(id()); }
//! \}
//! \name Element Index Accessors
//! \{
//! Returns whether the register has element index (it's an element index access).
ASMJIT_INLINE_CONSTEXPR bool has_element_index() const noexcept {
return _signature.has_field<kSignatureRegElementFlagMask>();
}
//! Returns element index of the register.
ASMJIT_INLINE_CONSTEXPR uint32_t element_index() const noexcept {
return _signature.get_field<kSignatureRegElementIndexMask>();
}
//! Sets element index of the register to `element_type`.
ASMJIT_INLINE_CONSTEXPR void set_element_index(uint32_t element_index) noexcept {
_signature |= kSignatureRegElementFlagMask;
_signature.set_field<kSignatureRegElementIndexMask>(element_index);
}
//! Resets element index of the register.
ASMJIT_INLINE_CONSTEXPR void reset_element_index() noexcept {
_signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
}
//! Clones a vector register with element access enabled at the given `element_index`.
[[nodiscard]]
ASMJIT_INLINE_CONSTEXPR Vec at(uint32_t element_index) const noexcept {
return Vec((signature() & ~kSignatureRegElementIndexMask) | (element_index << kSignatureRegElementIndexShift) | kSignatureRegElementFlagMask, id());
}
//! \}
};
//! Register-list of 32-bit GP registers.
class GpList : public RegListT<Gp> {
public:
//! \name Constants
//! \{
static inline constexpr uint32_t kSignature =
Signature::from_op_type(OperandType::kRegList).bits() | (RegTraits<RegType::kGp32>::kSignature & ~Signature::kOpTypeMask);
//! \}
//! \name Construction & Destruction
//! \{
//! Creates a dummy register-list operand.
ASMJIT_INLINE_NODEBUG constexpr GpList() noexcept
: RegListT<Gp>(Signature{kSignature}, RegMask(0)) {}
//! Creates a register-list operand which is the same as `other` .
ASMJIT_INLINE_NODEBUG constexpr GpList(const GpList& other) noexcept
: RegListT<Gp>(other) {}
//! Creates a register-list operand initialized to the given `regMask`.
ASMJIT_INLINE_NODEBUG explicit constexpr GpList(RegMask regMask) noexcept
: RegListT<Gp>(Signature{kSignature}, regMask) {}
//! Creates a register-list operand initialized to `regs`.
ASMJIT_INLINE_NODEBUG explicit GpList(std::initializer_list<Gp> regs) noexcept
: RegListT(Signature{kSignature}, regs) {}
ASMJIT_INLINE_NODEBUG explicit GpList(Globals::NoInit_) noexcept
: RegListT<Gp>(Globals::NoInit) {}
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_NODEBUG GpList& operator=(const GpList& other) noexcept = default;
ASMJIT_INLINE_NODEBUG GpList& operator|=(const GpList& other) noexcept { add_list(other); return *this; }
ASMJIT_INLINE_NODEBUG GpList& operator&=(const GpList& other) noexcept { and_list(other); return *this; }
ASMJIT_INLINE_NODEBUG GpList& operator^=(const GpList& other) noexcept { xor_list(other); return *this; }
ASMJIT_INLINE_NODEBUG GpList operator|(const GpList& other) const noexcept { return GpList(list() | other.list()); }
ASMJIT_INLINE_NODEBUG GpList operator&(const GpList& other) const noexcept { return GpList(list() & other.list()); }
ASMJIT_INLINE_NODEBUG GpList operator^(const GpList& other) const noexcept { return GpList(list() ^ other.list()); }
//! \}
};
//! Register-list of 32-bit (vector) S registers.
class VecSList : public RegListT<Vec> {
public:
//! \name Constants
//! \{
static inline constexpr uint32_t kSignature =
Signature::from_op_type(OperandType::kRegList).bits() | (RegTraits<RegType::kVec32>::kSignature & ~Signature::kOpTypeMask);
//! \}
//! \name Construction & Destruction
//! \{
//! Creates a dummy register-list operand.
ASMJIT_INLINE_NODEBUG constexpr VecSList() noexcept
: RegListT<Vec>(Signature{kSignature}, RegMask(0)) {}
//! Creates a register-list operand which is the same as `other` .
ASMJIT_INLINE_NODEBUG constexpr VecSList(const VecSList& other) noexcept
: RegListT<Vec>(other) {}
//! Creates a register-list operand initialized to the given `regMask`.
ASMJIT_INLINE_NODEBUG explicit constexpr VecSList(RegMask regMask) noexcept
: RegListT<Vec>(Signature{kSignature}, regMask) {}
//! Creates a register-list operand initialized to `regs`.
ASMJIT_INLINE_NODEBUG explicit VecSList(std::initializer_list<Vec> regs) noexcept
: RegListT(Signature{kSignature}, regs) {}
ASMJIT_INLINE_NODEBUG explicit VecSList(Globals::NoInit_) noexcept
: RegListT<Vec>(Globals::NoInit) {}
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_NODEBUG VecSList& operator=(const VecSList& other) noexcept = default;
ASMJIT_INLINE_NODEBUG VecSList& operator|=(const VecSList& other) noexcept { add_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecSList& operator&=(const VecSList& other) noexcept { and_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecSList& operator^=(const VecSList& other) noexcept { xor_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecSList operator|(const VecSList& other) const noexcept { return VecSList(list() | other.list()); }
ASMJIT_INLINE_NODEBUG VecSList operator&(const VecSList& other) const noexcept { return VecSList(list() & other.list()); }
ASMJIT_INLINE_NODEBUG VecSList operator^(const VecSList& other) const noexcept { return VecSList(list() ^ other.list()); }
//! \}
};
//! Register-list of 32-bit (vector) D registers.
class VecDList : public RegListT<Vec> {
public:
//! \name Constants
//! \{
static inline constexpr uint32_t kSignature =
Signature::from_op_type(OperandType::kRegList).bits() | (RegTraits<RegType::kVec64>::kSignature & ~Signature::kOpTypeMask);
//! \}
//! \name Construction & Destruction
//! \{
//! Creates a dummy register-list operand.
ASMJIT_INLINE_NODEBUG constexpr VecDList() noexcept
: RegListT<Vec>(Signature{kSignature}, RegMask(0)) {}
//! Creates a register-list operand which is the same as `other` .
ASMJIT_INLINE_NODEBUG constexpr VecDList(const VecDList& other) noexcept
: RegListT<Vec>(other) {}
//! Creates a register-list operand initialized to the given `regMask`.
ASMJIT_INLINE_NODEBUG explicit constexpr VecDList(RegMask regMask) noexcept
: RegListT<Vec>(Signature{kSignature}, regMask) {}
//! Creates a register-list operand initialized to `regs`.
ASMJIT_INLINE_NODEBUG explicit VecDList(std::initializer_list<Vec> regs) noexcept
: RegListT(Signature{kSignature}, regs) {}
ASMJIT_INLINE_NODEBUG explicit VecDList(Globals::NoInit_) noexcept
: RegListT<Vec>(Globals::NoInit) {}
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_NODEBUG VecDList& operator=(const VecDList& other) noexcept = default;
ASMJIT_INLINE_NODEBUG VecDList& operator|=(const VecDList& other) noexcept { add_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecDList& operator&=(const VecDList& other) noexcept { and_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecDList& operator^=(const VecDList& other) noexcept { xor_list(other); return *this; }
ASMJIT_INLINE_NODEBUG VecDList operator|(const VecDList& other) const noexcept { return VecDList(list() | other.list()); }
ASMJIT_INLINE_NODEBUG VecDList operator&(const VecDList& other) const noexcept { return VecDList(list() & other.list()); }
ASMJIT_INLINE_NODEBUG VecDList operator^(const VecDList& other) const noexcept { return VecDList(list() ^ other.list()); }
//! \}
};
//! Memory operand (AArch32).
class Mem : public BaseMem {
public:
//! \cond INTERNAL
// Index shift value (5 bits).
// |........|.....XXX|XX......|........|
static inline constexpr uint32_t kSignatureMemShiftValueShift = 14;
static inline constexpr uint32_t kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift;
// Index shift operation (4 bits).
// |........|XXXX....|........|........|
static inline constexpr uint32_t kSignatureMemShiftOpShift = 20;
static inline constexpr uint32_t kSignatureMemShiftOpMask = 0x0Fu << kSignatureMemShiftOpShift;
// Offset mode type (2 bits).
// |......XX|........|........|........|
static inline constexpr uint32_t kSignatureMemOffsetModeShift = 24;
static inline constexpr uint32_t kSignatureMemOffsetModeMask = 0x03u << kSignatureMemOffsetModeShift;
//! \endcond
//! \name Construction & Destruction
//! \{
//! Construct a default `Mem` operand, that points to [0].
ASMJIT_INLINE_CONSTEXPR Mem() noexcept
: BaseMem() {}
ASMJIT_INLINE_CONSTEXPR Mem(const Mem& other) noexcept
: BaseMem(other) {}
ASMJIT_INLINE_NODEBUG explicit Mem(Globals::NoInit_) noexcept
: BaseMem(Globals::NoInit) {}
ASMJIT_INLINE_CONSTEXPR Mem(const Signature& signature, uint32_t base_id, uint32_t index_id, int32_t offset) noexcept
: BaseMem(signature, base_id, index_id, offset) {}
ASMJIT_INLINE_CONSTEXPR explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::from_op_type(OperandType::kMem) |
Signature::from_mem_base_type(RegType::kLabelTag) |
signature, base.id(), 0, off) {}
ASMJIT_INLINE_CONSTEXPR explicit Mem(const Reg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::from_op_type(OperandType::kMem) |
Signature::from_mem_base_type(base.reg_type()) |
signature, base.id(), 0, off) {}
ASMJIT_INLINE_CONSTEXPR Mem(const Reg& base, const Reg& index, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::from_op_type(OperandType::kMem) |
Signature::from_mem_base_type(base.reg_type()) |
Signature::from_mem_index_type(index.reg_type()) |
signature, base.id(), index.id(), 0) {}
ASMJIT_INLINE_CONSTEXPR Mem(const Reg& base, const Reg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::from_op_type(OperandType::kMem) |
Signature::from_mem_base_type(base.reg_type()) |
Signature::from_mem_index_type(index.reg_type()) |
Signature::from_value<kSignatureMemShiftOpMask>(uint32_t(shift.op())) |
Signature::from_value<kSignatureMemShiftValueMask>(shift.value()) |
signature, base.id(), index.id(), 0) {}
ASMJIT_INLINE_CONSTEXPR explicit Mem(uint64_t base, Signature signature = Signature{0}) noexcept
: BaseMem(Signature::from_op_type(OperandType::kMem) |
signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_CONSTEXPR Mem& operator=(const Mem& other) noexcept {
copy_from(other);
return *this;
}
//! \}
//! \name Clone
//! \{
//! Clones the memory operand.
ASMJIT_INLINE_CONSTEXPR Mem clone() const noexcept { return Mem(*this); }
//! Gets new memory operand adjusted by `off`.
ASMJIT_INLINE_CONSTEXPR Mem clone_adjusted(int64_t off) const noexcept {
Mem result(*this);
result.add_offset(off);
return result;
}
//! Clones the memory operand and makes it pre-index.
ASMJIT_INLINE_CONSTEXPR Mem pre() const noexcept {
Mem result(*this);
result.set_offset_mode(OffsetMode::kPreIndex);
return result;
}
//! Clones the memory operand, applies a given offset `off` and makes it pre-index.
ASMJIT_INLINE_CONSTEXPR Mem pre(int64_t off) const noexcept {
Mem result(*this);
result.set_offset_mode(OffsetMode::kPreIndex);
result.add_offset(off);
return result;
}
//! Clones the memory operand and makes it post-index.
ASMJIT_INLINE_CONSTEXPR Mem post() const noexcept {
Mem result(*this);
result.set_offset_mode(OffsetMode::kPostIndex);
return result;
}
//! Clones the memory operand, applies a given offset `off` and makes it post-index.
ASMJIT_INLINE_CONSTEXPR Mem post(int64_t off) const noexcept {
Mem result(*this);
result.set_offset_mode(OffsetMode::kPostIndex);
result.add_offset(off);
return result;
}
//! \}
//! \name Base & Index
//! \{
//! Converts memory `base_type` and `base_id` to `arm::Reg` instance.
//!
//! The memory must have a valid base register otherwise the result will be wrong.
ASMJIT_INLINE_NODEBUG Reg base_reg() const noexcept { return Reg::from_type_and_id(base_type(), base_id()); }
//! Converts memory `index_type` and `index_id` to `arm::Reg` instance.
//!
//! The memory must have a valid index register otherwise the result will be wrong.
ASMJIT_INLINE_NODEBUG Reg index_reg() const noexcept { return Reg::from_type_and_id(index_type(), index_id()); }
using BaseMem::set_index;
ASMJIT_INLINE_CONSTEXPR void set_index(const Reg& index, uint32_t shift) noexcept {
set_index(index);
set_shift(shift);
}
ASMJIT_INLINE_CONSTEXPR void set_index(const Reg& index, Shift shift) noexcept {
set_index(index);
set_shift(shift);
}
//! \}
//! \name ARM Specific Features
//! \{
//! Gets offset mode.
ASMJIT_INLINE_CONSTEXPR OffsetMode offset_mode() const noexcept { return OffsetMode(_signature.get_field<kSignatureMemOffsetModeMask>()); }
//! Sets offset mode to `mode`.
ASMJIT_INLINE_CONSTEXPR void set_offset_mode(OffsetMode mode) noexcept { _signature.set_field<kSignatureMemOffsetModeMask>(uint32_t(mode)); }
//! Resets offset mode to default (fixed offset, without write-back).
ASMJIT_INLINE_CONSTEXPR void reset_offset_mode() noexcept { _signature.set_field<kSignatureMemOffsetModeMask>(uint32_t(OffsetMode::kFixed)); }
//! Tests whether the current memory offset mode is fixed (see \ref arm::OffsetMode::kFixed).
ASMJIT_INLINE_CONSTEXPR bool is_fixed_offset() const noexcept { return offset_mode() == OffsetMode::kFixed; }
//! Tests whether the current memory offset mode is either pre-index or post-index (write-back is used).
ASMJIT_INLINE_CONSTEXPR bool is_pre_or_post() const noexcept { return offset_mode() != OffsetMode::kFixed; }
//! Tests whether the current memory offset mode is pre-index (write-back is used).
ASMJIT_INLINE_CONSTEXPR bool is_pre_index() const noexcept { return offset_mode() == OffsetMode::kPreIndex; }
//! Tests whether the current memory offset mode is post-index (write-back is used).
ASMJIT_INLINE_CONSTEXPR bool is_post_index() const noexcept { return offset_mode() == OffsetMode::kPostIndex; }
//! Sets offset mode of this memory operand to pre-index (write-back is used).
ASMJIT_INLINE_CONSTEXPR void make_pre_index() noexcept { set_offset_mode(OffsetMode::kPreIndex); }
//! Sets offset mode of this memory operand to post-index (write-back is used).
ASMJIT_INLINE_CONSTEXPR void make_post_index() noexcept { set_offset_mode(OffsetMode::kPostIndex); }
//! Gets shift operation that is used by index register.
ASMJIT_INLINE_CONSTEXPR ShiftOp shift_op() const noexcept { return ShiftOp(_signature.get_field<kSignatureMemShiftOpMask>()); }
//! Sets shift operation that is used by index register.
ASMJIT_INLINE_CONSTEXPR void set_shift_op(ShiftOp sop) noexcept { _signature.set_field<kSignatureMemShiftOpMask>(uint32_t(sop)); }
//! Resets shift operation that is used by index register to LSL (default value).
ASMJIT_INLINE_CONSTEXPR void reset_shift_op() noexcept { _signature.set_field<kSignatureMemShiftOpMask>(uint32_t(ShiftOp::kLSL)); }
//! Gets whether the memory operand has shift (aka scale) constant.
ASMJIT_INLINE_CONSTEXPR bool has_shift() const noexcept { return _signature.has_field<kSignatureMemShiftValueMask>(); }
//! Gets the memory operand's shift (aka scale) constant.
ASMJIT_INLINE_CONSTEXPR uint32_t shift() const noexcept { return _signature.get_field<kSignatureMemShiftValueMask>(); }
//! Sets the memory operand's shift (aka scale) constant.
ASMJIT_INLINE_CONSTEXPR void set_shift(uint32_t shift) noexcept { _signature.set_field<kSignatureMemShiftValueMask>(shift); }
//! Sets the memory operand's shift and shift operation.
ASMJIT_INLINE_CONSTEXPR void set_shift(Shift shift) noexcept {
_signature.set_field<kSignatureMemShiftOpMask>(uint32_t(shift.op()));
_signature.set_field<kSignatureMemShiftValueMask>(shift.value());
}
//! Resets the memory operand's shift (aka scale) constant to zero.
ASMJIT_INLINE_CONSTEXPR void reset_shift() noexcept { _signature.set_field<kSignatureMemShiftValueMask>(0); }
//! \}
};
#ifndef _DOXYGEN
namespace regs {
#endif
//! Creates a 32-bit R register operand.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp r(uint32_t id) noexcept { return Gp::make_r32(id); }
//! Creates a 32-bit S register operand.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec s(uint32_t id) noexcept { return Vec::make_v32(id); }
//! Creates a 64-bit D register operand.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec d(uint32_t id) noexcept { return Vec::make_v64(id); }
//! Creates a 128-bit V register operand.
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Vec q(uint32_t id) noexcept { return Vec::make_v128(id); }
static constexpr Gp r0 = Gp::make_r32(0);
static constexpr Gp r1 = Gp::make_r32(1);
static constexpr Gp r2 = Gp::make_r32(2);
static constexpr Gp r3 = Gp::make_r32(3);
static constexpr Gp r4 = Gp::make_r32(4);
static constexpr Gp r5 = Gp::make_r32(5);
static constexpr Gp r6 = Gp::make_r32(6);
static constexpr Gp r7 = Gp::make_r32(7);
static constexpr Gp r8 = Gp::make_r32(8);
static constexpr Gp r9 = Gp::make_r32(9);
static constexpr Gp r10 = Gp::make_r32(10);
static constexpr Gp r11 = Gp::make_r32(11);
static constexpr Gp r12 = Gp::make_r32(12);
static constexpr Gp r13 = Gp::make_r32(13);
static constexpr Gp r14 = Gp::make_r32(14);
static constexpr Gp r15 = Gp::make_r32(15);
static constexpr Gp fp = Gp::make_r32(Gp::kIdFP);
static constexpr Gp sp = Gp::make_r32(Gp::kIdSP);
static constexpr Gp lr = Gp::make_r32(Gp::kIdLR);
static constexpr Gp pc = Gp::make_r32(Gp::kIdPC);
static constexpr Vec s0 = Vec::make_v32(0);
static constexpr Vec s1 = Vec::make_v32(1);
static constexpr Vec s2 = Vec::make_v32(2);
static constexpr Vec s3 = Vec::make_v32(3);
static constexpr Vec s4 = Vec::make_v32(4);
static constexpr Vec s5 = Vec::make_v32(5);
static constexpr Vec s6 = Vec::make_v32(6);
static constexpr Vec s7 = Vec::make_v32(7);
static constexpr Vec s8 = Vec::make_v32(8);
static constexpr Vec s9 = Vec::make_v32(9);
static constexpr Vec s10 = Vec::make_v32(10);
static constexpr Vec s11 = Vec::make_v32(11);
static constexpr Vec s12 = Vec::make_v32(12);
static constexpr Vec s13 = Vec::make_v32(13);
static constexpr Vec s14 = Vec::make_v32(14);
static constexpr Vec s15 = Vec::make_v32(15);
static constexpr Vec s16 = Vec::make_v32(16);
static constexpr Vec s17 = Vec::make_v32(17);
static constexpr Vec s18 = Vec::make_v32(18);
static constexpr Vec s19 = Vec::make_v32(19);
static constexpr Vec s20 = Vec::make_v32(20);
static constexpr Vec s21 = Vec::make_v32(21);
static constexpr Vec s22 = Vec::make_v32(22);
static constexpr Vec s23 = Vec::make_v32(23);
static constexpr Vec s24 = Vec::make_v32(24);
static constexpr Vec s25 = Vec::make_v32(25);
static constexpr Vec s26 = Vec::make_v32(26);
static constexpr Vec s27 = Vec::make_v32(27);
static constexpr Vec s28 = Vec::make_v32(28);
static constexpr Vec s29 = Vec::make_v32(29);
static constexpr Vec s30 = Vec::make_v32(30);
static constexpr Vec s31 = Vec::make_v32(31);
static constexpr Vec d0 = Vec::make_v64(0);
static constexpr Vec d1 = Vec::make_v64(1);
static constexpr Vec d2 = Vec::make_v64(2);
static constexpr Vec d3 = Vec::make_v64(3);
static constexpr Vec d4 = Vec::make_v64(4);
static constexpr Vec d5 = Vec::make_v64(5);
static constexpr Vec d6 = Vec::make_v64(6);
static constexpr Vec d7 = Vec::make_v64(7);
static constexpr Vec d8 = Vec::make_v64(8);
static constexpr Vec d9 = Vec::make_v64(9);
static constexpr Vec d10 = Vec::make_v64(10);
static constexpr Vec d11 = Vec::make_v64(11);
static constexpr Vec d12 = Vec::make_v64(12);
static constexpr Vec d13 = Vec::make_v64(13);
static constexpr Vec d14 = Vec::make_v64(14);
static constexpr Vec d15 = Vec::make_v64(15);
static constexpr Vec d16 = Vec::make_v64(16);
static constexpr Vec d17 = Vec::make_v64(17);
static constexpr Vec d18 = Vec::make_v64(18);
static constexpr Vec d19 = Vec::make_v64(19);
static constexpr Vec d20 = Vec::make_v64(20);
static constexpr Vec d21 = Vec::make_v64(21);
static constexpr Vec d22 = Vec::make_v64(22);
static constexpr Vec d23 = Vec::make_v64(23);
static constexpr Vec d24 = Vec::make_v64(24);
static constexpr Vec d25 = Vec::make_v64(25);
static constexpr Vec d26 = Vec::make_v64(26);
static constexpr Vec d27 = Vec::make_v64(27);
static constexpr Vec d28 = Vec::make_v64(28);
static constexpr Vec d29 = Vec::make_v64(29);
static constexpr Vec d30 = Vec::make_v64(30);
static constexpr Vec d31 = Vec::make_v64(31);
static constexpr Vec q0 = Vec::make_v128(0);
static constexpr Vec q1 = Vec::make_v128(1);
static constexpr Vec q2 = Vec::make_v128(2);
static constexpr Vec q3 = Vec::make_v128(3);
static constexpr Vec q4 = Vec::make_v128(4);
static constexpr Vec q5 = Vec::make_v128(5);
static constexpr Vec q6 = Vec::make_v128(6);
static constexpr Vec q7 = Vec::make_v128(7);
static constexpr Vec q8 = Vec::make_v128(8);
static constexpr Vec q9 = Vec::make_v128(9);
static constexpr Vec q10 = Vec::make_v128(10);
static constexpr Vec q11 = Vec::make_v128(11);
static constexpr Vec q12 = Vec::make_v128(12);
static constexpr Vec q13 = Vec::make_v128(13);
static constexpr Vec q14 = Vec::make_v128(14);
static constexpr Vec q15 = Vec::make_v128(15);
#ifndef _DOXYGEN
} // {regs}
// Make `a32::regs` accessible through `a32` namespace as well.
using namespace regs;
#endif
//! \name Shift Operation Construction
//! \{
//! Constructs a `LSL #value` shift (logical shift left).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp lsl(const Gp& gp) noexcept { return gp.shifted(ShiftOp::kLSL); }
//! Constructs a `LSR #value` shift (logical shift right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp lsr(const Gp& gp) noexcept { return gp.shifted(ShiftOp::kLSR); }
//! Constructs a `ASR #value` shift (arithmetic shift right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp asr(const Gp& gp) noexcept { return gp.shifted(ShiftOp::kASR); }
//! Constructs a `ROR #value` shift (rotate right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Gp ror(const Gp& gp) noexcept { return gp.shifted(ShiftOp::kROR); }
//! Constructs a `LSL #value` shift (logical shift left).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
//! Constructs a `LSR #value` shift (logical shift right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
//! Constructs a `ASR #value` shift (arithmetic shift right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
//! Constructs a `ROR #value` shift (rotate right).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
//! \}
//! \name Memory Operand Construction
//! \{
//! Creates `[base, offset]` memory operand (offset mode) (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
//! Creates `[base, offset]!` memory operand (pre-index mode) (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr_pre(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::from_value<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPreIndex));
}
//! Creates `[base], offset` memory operand (post-index mode) (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr_post(const Gp& base, int32_t offset = 0) noexcept {
return Mem(base, offset, OperandSignature::from_value<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPostIndex));
}
//! Creates `[base, index]` memory operand (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr(const Gp& base, const Gp& index) noexcept {
return Mem(base, index);
}
//! Creates `[base, index]!` memory operand (pre-index mode) (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr_pre(const Gp& base, const Gp& index) noexcept {
return Mem(base, index, OperandSignature::from_value<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPreIndex));
}
//! Creates `[base], index` memory operand (post-index mode) (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr_post(const Gp& base, const Gp& index) noexcept {
return Mem(base, index, OperandSignature::from_value<Mem::kSignatureMemOffsetModeMask>(OffsetMode::kPostIndex));
}
//! Creates `[base, index, SHIFT_OP #shift]` memory operand (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr(const Gp& base, const Gp& index, const Shift& shift) noexcept {
return Mem(base, index, shift);
}
//! Creates `[base, offset]` memory operand (AArch32).
[[nodiscard]]
static ASMJIT_INLINE_CONSTEXPR Mem ptr(const Label& base, int32_t offset = 0) noexcept {
return Mem(base, offset);
}
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // ASMJIT_ARM_A32OPERAND_H_INCLUDED

View File

@@ -10,6 +10,7 @@
#include <asmjit/core/misc_p.h>
#include <asmjit/support/support.h>
#include <asmjit/arm/armformatter_p.h>
#include <asmjit/arm/a32operand.h>
#include <asmjit/arm/a64operand.h>
#include <asmjit/arm/a64instapi_p.h>
#include <asmjit/arm/a64instdb_p.h>
@@ -395,6 +396,15 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::format_register(
}
else {
letter = 'r';
if (reg_id == a32::Gp::kIdSP)
return sb.append("sp", 2);
if (reg_id == a32::Gp::kIdLR)
return sb.append("lr", 2);
if (reg_id == a32::Gp::kIdPC)
return sb.append("pc", 2);
}
break;

View File

@@ -102,6 +102,12 @@
#define ASMJIT_NO_X86
#undef ASMJIT_NO_X86
//! \def ASMJIT_NO_AARCH32
//!
//! Disables AArch32 backend.
#define ASMJIT_NO_AARCH32
#undef ASMJIT_NO_AARCH32
//! \def ASMJIT_NO_AARCH64
//!
//! Disables AArch64 backend.
@@ -304,6 +310,10 @@
#define ASMJIT_NO_X86
#endif
#if ASMJIT_ARCH_ARM != 32 && !defined(ASMJIT_NO_AARCH32)
#define ASMJIT_NO_AARCH32
#endif
#if ASMJIT_ARCH_ARM != 64 && !defined(ASMJIT_NO_AARCH64)
#define ASMJIT_NO_AARCH64
#endif

View File

@@ -261,6 +261,10 @@ static ASMJIT_INLINE_NODEBUG uint32_t data_type_size(DataType dt) noexcept {
ASMJIT_END_SUB_NAMESPACE
ASMJIT_BEGIN_SUB_NAMESPACE(a32)
using namespace arm;
ASMJIT_END_SUB_NAMESPACE
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
using namespace arm;
ASMJIT_END_SUB_NAMESPACE

View File

@@ -12,6 +12,10 @@
#include <asmjit/x86/x86archtraits_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/arm/a32archtraits_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH64)
#include <asmjit/arm/a64archtraits_p.h>
#endif
@@ -74,7 +78,11 @@ ASMJIT_VARAPI const ArchTraits _arch_traits[uint32_t(Arch::kMaxValue) + 1] = {
no_arch_traits,
// ARM architecture
#if !defined(ASMJIT_NO_AARCH32)
a32::a32_arch_traits,
#else
no_arch_traits,
#endif
// AArch64 architecture.
#if !defined(ASMJIT_NO_AARCH64)
@@ -84,7 +92,11 @@ ASMJIT_VARAPI const ArchTraits _arch_traits[uint32_t(Arch::kMaxValue) + 1] = {
#endif
// ARM/Thumb architecture.
#if !defined(ASMJIT_NO_AARCH32)
a32::a32_arch_traits,
#else
no_arch_traits,
#endif
// Reserved.
no_arch_traits,

View File

@@ -20,6 +20,10 @@
#include <asmjit/x86/x86formatter_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/arm/a32formatter_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH64)
#include <asmjit/arm/a64formatter_p.h>
#endif
@@ -126,7 +130,7 @@ Error format_feature(String& sb, Arch arch, uint32_t feature_id) noexcept {
}
#endif
#if !defined(ASMJIT_NO_AARCH64)
#if !defined(ASMJIT_NO_AARCH32) && !defined(ASMJIT_NO_AARCH64)
if (Environment::is_family_arm(arch)) {
return arm::FormatterInternal::format_feature(sb, feature_id);
}
@@ -184,7 +188,7 @@ Error format_register(
}
#endif
#if !defined(ASMJIT_NO_AARCH64)
#if !defined(ASMJIT_NO_AARCH32) || !defined(ASMJIT_NO_AARCH64)
if (Environment::is_family_arm(arch)) {
return arm::FormatterInternal::format_register(sb, format_flags, emitter, arch, reg_type, reg_id);
}
@@ -206,7 +210,7 @@ Error format_operand(
}
#endif
#if !defined(ASMJIT_NO_AARCH64)
#if !defined(ASMJIT_NO_AARCH32) || !defined(ASMJIT_NO_AARCH64)
if (Environment::is_family_arm(arch)) {
return arm::FormatterInternal::format_operand(sb, format_flags, emitter, arch, op);
}
@@ -318,6 +322,11 @@ Error format_instruction(
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::FormatterInternal::format_instruction(sb, format_flags, emitter, arch, inst, operands);
#endif
return make_error(Error::kInvalidArch);
}

View File

@@ -11,6 +11,10 @@
#include <asmjit/x86/x86instapi_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH32)
#include <asmjit/arm/a32instapi_p.h>
#endif
#if !defined(ASMJIT_NO_AARCH64)
#include <asmjit/arm/a64instapi_p.h>
#endif
@@ -34,6 +38,11 @@ Error InstAPI::inst_id_to_string(Arch arch, InstId inst_id, InstStringifyOptions
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::InstInternal::inst_id_to_string(inst_id, options, output);
#endif
return make_error(Error::kInvalidArch);
}
@@ -50,6 +59,11 @@ InstId InstAPI::string_to_inst_id(Arch arch, const char* s, size_t len) noexcept
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::InstInternal::string_to_inst_id(s, len);
#endif
return 0;
}
#endif // !ASMJIT_NO_TEXT
@@ -76,6 +90,10 @@ Error InstAPI::validate(Arch arch, const BaseInst& inst, const Operand_* operand
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::InstInternal::validate(inst, operands, op_count, validation_flags);
#endif
return make_error(Error::kInvalidArch);
}
#endif // !ASMJIT_NO_INTROSPECTION
@@ -101,6 +119,11 @@ Error InstAPI::query_rw_info(Arch arch, const BaseInst& inst, const Operand_* op
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::InstInternal::query_rw_info(inst, operands, op_count, out);
#endif
return make_error(Error::kInvalidArch);
}
#endif // !ASMJIT_NO_INTROSPECTION
@@ -122,6 +145,11 @@ Error InstAPI::query_features(Arch arch, const BaseInst& inst, const Operand_* o
}
#endif
#if !defined(ASMJIT_NO_AARCH32)
if (Environment::is_family_aarch32(arch))
return a32::InstInternal::query_features(inst, operands, op_count, out);
#endif
return make_error(Error::kInvalidArch);
}
#endif // !ASMJIT_NO_INTROSPECTION

View File

@@ -17,7 +17,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
_arch_mask = (uint64_t(1) << uint32_t(Arch::kX86)) |
(uint64_t(1) << uint32_t(Arch::kX64)) ;
(uint64_t(1) << uint32_t(Arch::kX64)) ;
init_emitter_funcs(this);
if (code) {

View File

@@ -18,7 +18,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
Compiler::Compiler(CodeHolder* code) noexcept : BaseCompiler() {
_arch_mask = (uint64_t(1) << uint32_t(Arch::kX86)) |
(uint64_t(1) << uint32_t(Arch::kX64)) ;
(uint64_t(1) << uint32_t(Arch::kX64)) ;
init_emitter_funcs(this);
if (code) {

1622
tools/tablegen-a32.js Normal file

File diff suppressed because it is too large Load Diff

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

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

417
tools/testgen-a32.js Normal file
View File

@@ -0,0 +1,417 @@
// This file is part of AsmJit project <https://asmjit.com>
//
// See asmjit.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
"use strict";
const core = require("./tablegen.js");
const isa = new core.asmdb.aarch32.ISA();
const LLVM_MC = "/home/petr/workspace/3rdparty/llvm-project-build/bin/llvm-mc";
function lsbFromMul(mul) {
for (let i = 0; i < 32; i++)
if ((mul & (1 << i)) != 0)
return i;
return 32;
}
class TestsGenerator {
constructor(isa) {
this.isa = isa;
}
generate() {
const child_process = require("child_process");
const tests = {
"gp": [],
"vec": []
};
function flatten(inputArray) {
const outputArray = [inputArray];
let i = 0;
while (i < outputArray.length) {
let didFlatten = false;
const items = outputArray[i];
for (let j = 0; j < items.length; j++) {
if (Array.isArray(items[j])) {
const flattenedItems = [];
for (let k = 0; k < items[j].length; k++) {
const copy = items.slice();
copy[j] = items[j][k];
flattenedItems.push(copy);
}
outputArray.splice(i, 1, ...flattenedItems);
didFlatten = true;
break;
}
}
i += Number(!didFlatten);
}
return outputArray;
}
function makeShiftOp(sop, op) {
if (sop === "sop")
return ["lsl " + op, "lsr " + op, "asr " + op, "ror " + op];
else if (sop === "lsl_or_asr")
return ["lsl " + op, "asr " + op];
else
return sop + " " + op;
}
function encodingFromText(s) {
let m = s.match(/@\s*encoding\:\s*\[0x([\w]{2}),0x([\w]{2}),0x([\w]{2}),0x([\w]{2})\]/);
if (m)
return ('"' + m[1] + m[2] + m[3] + m[4] + '"').toUpperCase();
else
return null;
}
function codeFromInstruction(s) {
s = s.trim();
var sIdx = s.indexOf(" ");
var name = s.substr(0, sIdx !== -1 ? sIdx : s.length).replace(/\./g, "_");
var operands = s.substr(name.length).trim();
var sops = operands.replace(/(v\d+)\.(\d+)?([a-z]+)\[(\d+)\]/g, "$1.$3$2($4)")
.replace(/([d|s|q]\d+)\[(\d+)\]/g, "$1.at($2)")
.replace(/\[(\w+),\s*[#]?([-]?\w+)\]!/g, "ptr_pre($1, $2)")
.replace(/\[(\w+)\],\s*[#]?([-]?\w+)/g, "ptr_post($1, $2)")
.replace(/\[(\w+),\s*[#]?([-]?\w+)\]/g, "ptr($1, $2)")
.replace(/\[(\w+)\]/g, "ptr($1)")
.replace(/\beq\b/g, "Cond::kEQ")
.replace(/#((?:0x)?[-]?[\dA-Fa-f]+)\b/g, "$1")
.replace(/(lsl|lsr|asr|ror)\s+([r]?\d+)/g, "$1($2)")
.replace(/[{}]/g, "");
if (name === "and")
name = "and_";
return name + "(" + sops + ")";
}
for (let inst of isa.instructions) {
if (inst.encoding !== "A32")
continue;
let category = "gp";
let elements = [""];
const dt1Array = inst.dt.length ? inst.dt : ["any"];
const dt2Array = inst.dt2.length ? inst.dt2 : ["any"];
const dataTypes = [];
for (let dt2 of dt2Array) {
for (let dt1 of dt1Array) {
if (dt2 !== "any")
dataTypes.push(`.${dt1}.${dt2}`);
else if (dt1 !== "any")
dataTypes.push(`.${dt1}`);
else
dataTypes.push(``);
}
}
for (let dataType of dataTypes) {
let instruction = inst.name + dataType;
let ops = [];
let proceed = true;
for (let i = 0; i < inst.operands.length; i++) {
const operand = inst.operands[i];
let regId = i + 1;
if (/^(ldaexd|ldrd|ldrexd|strd)$/.test(inst.name)) {
regId--;
}
else if (/^(stlexd|strexd)$/.test(inst.name)) {
if (i == 0)
regId = 7;
else
regId = i - 1;
}
switch (operand.type) {
case "reg": {
if (operand.regType === "r" && operand.shiftOp) {
ops.push(makeShiftOp(operand.shiftOp, `r${i + 1}`));
}
else if (operand.regType === "r") {
ops.push(`r${regId}`);
}
else if (operand.regType === "s") {
ops.push(`s${regId}`);
category = "vec";
}
else if (operand.regType === "d") {
ops.push(`d${regId}`);
category = "vec";
}
else if (operand.regType === "v") {
ops.push(`q${regId}`);
category = "vec";
}
else {
proceed = false;
}
if (operand.element) {
ops[ops.length - 1] += "[@element@]";
switch (dataType) {
case ".8":
case ".s8":
case ".u8":
elements = [0, 1, 2, 3, 4, 5, 6, 7];
break;
case ".16":
case ".s16":
case ".u16":
case ".f16":
if (inst.name === "vcmla" || inst.name === "vfmsl" || inst.name === "vfmal")
elements = [0, 1];
else
elements = [0, 1, 2, 3];
break;
case ".32":
case ".s32":
case ".u32":
case ".f32":
if (inst.name === "vcmla")
elements = [0];
else
elements = [0, 1];
break;
case ".64":
case ".s64":
case ".u64":
case ".f64":
elements = [0, 1];
break;
case ".bf16":
if (inst.name === "vdot")
elements = [0, 1];
else
elements = [0, 1, 2, 3];
break;
}
}
break;
}
case "imm": {
if (inst.name === "vcadd")
ops.push(["#90", "#270"]);
else if (inst.name === "vcmla")
ops.push(["#0", "#90", "#180", "#270"]);
else if (operand.shiftOp)
ops.push(makeShiftOp(operand.shiftOp, "#8"));
else if (operand.imm === "zero")
ops.push("#0");
else if (operand.imm === "immA")
ops.push(["#0xFF", "0xFF00", "0xFF000000", "0xF000000F"]);
else if (operand.imm === "immZ")
ops.push("#1");
else if (operand.imm === "immV" && instruction.endsWith("16"))
ops.push(["#0x1F", "#0x80", "#0xFF", "0x1F00", "0xFF00"]);
else if (operand.imm === "immV" && instruction.endsWith("32"))
ops.push(["#0x1F", "#0x80", "#0xFF", "0x1F00", "0xFF00", "0x1F0000", "0xFF0000", "0xFF000000", "0xFFFF0000", "0x0000FFFF", "0xFFFFFF00", "0x00FFFFFF", "0xC0F00000"]);
else if (operand.imm === "immV" && instruction.endsWith("64"))
ops.push(["#00FFFF0000000000", "#0xFF00FF0000000000", "#0x00000000FFFFFFFF"]);
else if (operand.imm === "lsb")
ops.push("#3");
else if (operand.imm === "width")
ops.push("#5");
else if (operand.imm === "sat")
ops.push("#8");
else if (operand.imm === "imm")
ops.push("#0");
else if (operand.imm === "n")
ops.push("#3");
else
proceed = false;
break;
}
case "mem": {
const combinations = [];
var off = "4";
if (operand.offset && operand.offset.exp) {
const e = operand.offset.exp;
if (e.op === "==") {
off = e.right.toString();
if (off.indexOf("sz") !== -1 && dataType) {
const sz = dataType.match(/(\d+)/);
off = eval(off.replace("sz", parseInt(lsbFromMul(sz[1] / 8))));
}
}
}
if (operand.memModes.offset) {
if (operand.index)
combinations.push(`[r${regId}, r${regId + 1}]`);
else if (operand.offset)
combinations.push(`[r${regId}, #${off}]`);
else
combinations.push(`[r${regId}]`);
}
if (operand.memModes.preIndex) {
if (operand.index)
combinations.push(`[r${regId}, r${regId + 1}]!`);
else if (operand.offset)
combinations.push(`[r${regId}, #${off}]!`);
}
if (operand.memModes.postIndex) {
if (operand.index)
combinations.push(`[r${regId}], r${regId + 1}`);
else if (operand.offset)
combinations.push(`[r${regId}], #${off}`);
}
ops.push(combinations);
break;
}
default: {
proceed = false;
break;
}
}
}
if (!proceed) {
console.log(`IGNORING: ${inst.name}`);
continue;
}
const opsArray = flatten(ops);
const args = [
"--arch=arm",
"-mattr=+v8.5a",
"-mattr=+aes",
"-mattr=+bf16",
"-mattr=+crc",
"-mattr=+crypto",
"-mattr=+hwdiv-arm",
"-mattr=+fp16fml",
"-mattr=+fullfp16",
"-mattr=+i8mm",
"-mattr=+mp",
"-mattr=+trustzone",
"-mattr=+virtualization",
"-show-encoding",
"-output-asm-variant=0"
];
for (let element of elements) {
for (let opsRow of opsArray) {
let line = instruction;
opsRow = opsRow.map(function(s) { return s.replace("@element@", element) });
let o = opsRow.slice();
switch (inst.name) {
case "pop":
case "push": {
o[0] = "{" + o[0];
o[o.length - 1] += "}";
break;
}
case "vcls": {
line = line.replace(".u", ".s");
break;
}
case "vtbx":
case "vtbl": {
o[1] = "{" + o[1];
o[o.length - 2] += "}";
break;
}
case "rfe":
case "rfeda":
case "rfedb":
case "rfeib": {
o[0] = o[0].replace(/[\[\]]/g, "");
break;
}
case "vld1r":
case "vld2r":
case "vld3r":
case "vld4r": {
line = line.replace("vld1r", "vld1")
.replace("vld2r", "vld2")
.replace("vld3r", "vld3")
.replace("vld4r", "vld4");
for (let i = 0; i < o.length - 1; i++)
o[i] += "[]";
// fallthrough;
}
case "vld1":
case "vld2":
case "vld3":
case "vld4":
case "vst1":
case "vst2":
case "vst3":
case "vst4": {
o[o.length - 1] = o[o.length - 1].replace(/,\s*#\d+$/g, "!");
o[0] = "{" + o[0];
o[o.length - 2] += "}";
break;
}
}
try {
const out = child_process.execFileSync(LLVM_MC, args, {
input: line + " " + o.join(", "),
encoding: "utf-8"
});
const encoding = encodingFromText(out);
const code = codeFromInstruction(instruction + " " + opsRow.join(", "));
tests[category].push(`TEST_INSTRUCTION(${encoding}, ${code});`);
}
catch (ex) {
console.log(`FATAL: ${line} ${opsRow.join(", ")}`);
}
}
}
}
}
console.log("static void ASMJIT_NOINLINE testA32AssemblerGp(AssemblerTester<a32::Assembler>& tester) noexcept {");
console.log(" using namespace a32;");
console.log("");
for (let test of tests.gp) {
console.log(" " + test);
}
console.log("}");
console.log("");
console.log("static void ASMJIT_NOINLINE testA32AssemblerVec(AssemblerTester<a32::Assembler>& tester) noexcept {");
console.log(" using namespace a32;");
console.log("");
for (let test of tests.vec)
console.log(" " + test);
console.log("}");
}
}
new TestsGenerator(isa).generate();