mirror of
https://github.com/asmjit/asmjit
synced 2026-06-08 13:13:30 +00:00
b56f4176cb
* Denested src folder to root, renamed testing to asmjit-testing
* Refactored how headers are included into <asmjit/...> form. This
is necessary as compilers would never simplify a path once a ..
appears in include directory - then paths such as ../core/../core
appeared in asserts, which was ugly
* Moved support utilities into asmjit/support/... (still included
by asmjit/core.h for convenience and compatibility)
* Added CMakePresets.json for making it easy to develop AsmJit
* Reworked CMakeLists to be shorter and use CMake option(),
etc... This simplifies it and makes it using more standard
features
* ASMJIT_EMBED now creates asmjit_embed INTERFACE library,
which is accessible via asmjit::asmjit target - this simplifies
embedding and makes it the same as library targets from a CMake
perspective
* Removed ASMJIT_DEPS - this is now provided by cmake target
aliases - 'asmjit::asmjit' so users should not need this variable
* Changed meaning of ASMJIT_LIBS - this now contains only AsmJit
dependencies without asmjit::asmjit target alias. Don't rely on
ASMJIT_LIBS anymore as it's only used internally
* Removed ASMJIT_NO_DEPRECATED option - AsmJit is not going
to provide controllable deprecations in the future
* Removed ASMJIT_NO_VALIDATION in favor of ASMJIT_NO_INTROSPECTION,
which now controls query, features, and validation API presence
* Removed ASMJIT_DIR option - it was never really needed
* Removed AMX_TRANSPOSE feature from instruction database (X86).
Intel has removed it as well, so it's a feature that won't
be siliconized
253 lines
7.5 KiB
C++
253 lines
7.5 KiB
C++
// 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/api-build_p.h>
|
|
#if !defined(ASMJIT_NO_AARCH64)
|
|
|
|
#include <asmjit/core/cpuinfo.h>
|
|
#include <asmjit/core/misc_p.h>
|
|
#include <asmjit/support/support_p.h>
|
|
#include <asmjit/arm/a64instapi_p.h>
|
|
#include <asmjit/arm/a64instdb_p.h>
|
|
#include <asmjit/arm/a64operand.h>
|
|
|
|
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
|
|
|
namespace InstInternal {
|
|
|
|
// a64::InstInternal - 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 {
|
|
if (ASMJIT_UNLIKELY(!s)) {
|
|
return BaseInst::kIdNone;
|
|
}
|
|
|
|
if (len == SIZE_MAX) {
|
|
len = strlen(s);
|
|
}
|
|
|
|
if (len == 0u || len > InstDB::_inst_name_index.max_name_length) {
|
|
return BaseInst::kIdNone;
|
|
}
|
|
|
|
return InstNameUtils::find_instruction(s, len, InstDB::_inst_name_index_table, InstDB::_inst_name_string_table, InstDB::_inst_name_index);
|
|
}
|
|
#endif // !ASMJIT_NO_TEXT
|
|
|
|
// a64::InstInternal - Validate
|
|
// ============================
|
|
|
|
#ifndef ASMJIT_NO_INTROSPECTION
|
|
ASMJIT_FAVOR_SIZE Error validate(const BaseInst& inst, const Operand_* operands, size_t op_count, ValidationFlags validation_flags) noexcept {
|
|
// TODO:
|
|
Support::maybe_unused(inst, operands, op_count, validation_flags);
|
|
return Error::kOk;
|
|
}
|
|
#endif // !ASMJIT_NO_INTROSPECTION
|
|
|
|
// a64::InstInternal - QueryRWInfo
|
|
// ===============================
|
|
|
|
#ifndef ASMJIT_NO_INTROSPECTION
|
|
struct InstRWInfoData {
|
|
uint8_t rwx[Globals::kMaxOpCount];
|
|
};
|
|
|
|
static const InstRWInfoData inst_rw_info_table[] = {
|
|
#define R uint8_t(OpRWFlags::kRead)
|
|
#define W uint8_t(OpRWFlags::kWrite)
|
|
#define X uint8_t(OpRWFlags::kRW)
|
|
|
|
{{ R, R, R, R, R, R }}, // kRWI_R
|
|
{{ R, W, R, R, R, R }}, // kRWI_RW
|
|
{{ R, X, R, R, R, R }}, // kRWI_RX
|
|
{{ R, R, W, R, R, R }}, // kRWI_RRW
|
|
{{ R, W, X, R, R, R }}, // kRWI_RWX
|
|
{{ W, R, R, R, R, R }}, // kRWI_W
|
|
{{ W, R, W, R, R, R }}, // kRWI_WRW
|
|
{{ W, R, X, R, R, R }}, // kRWI_WRX
|
|
{{ W, R, R, W, R, R }}, // kRWI_WRRW
|
|
{{ W, R, R, X, R, R }}, // kRWI_WRRX
|
|
{{ W, W, R, R, R, R }}, // kRWI_WW
|
|
{{ X, R, R, R, R, R }}, // kRWI_X
|
|
{{ X, R, X, R, R, R }}, // kRWI_XRX
|
|
{{ X, X, R, R, X, R }}, // kRWI_XXRRX
|
|
|
|
{{ W, R, R, R, R, R }}, // kRWI_LDn
|
|
{{ R, W, R, R, R, R }}, // kRWI_STn
|
|
{{ R, R, R, R, R, R }} // kRWI_TODO
|
|
|
|
#undef R
|
|
#undef W
|
|
#undef X
|
|
};
|
|
|
|
static const uint8_t element_type_size_table[8] = { 0, 1, 2, 4, 8, 4, 4, 0 };
|
|
|
|
Error query_rw_info(const BaseInst& inst, const Operand_* operands, size_t op_count, InstRWInfo* out) noexcept {
|
|
// Get the instruction data.
|
|
uint32_t real_id = inst.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; // TODO: [ARM] Read PSTATUS.
|
|
out->_write_flags = CpuRWFlags::kNone; // TODO: [ARM] Write PSTATUS
|
|
|
|
const InstDB::InstInfo& inst_info = InstDB::_inst_info_table[real_id];
|
|
const InstRWInfoData& rw_info = inst_rw_info_table[inst_info.rw_info_index()];
|
|
|
|
if (inst_info.has_flag(InstDB::kInstFlagConsecutive) && op_count > 2) {
|
|
for (uint32_t i = 0; i < op_count; i++) {
|
|
OpRWInfo& op = out->_operands[i];
|
|
const Operand_& src_op = operands[i];
|
|
|
|
if (!src_op.is_reg_or_mem()) {
|
|
op.reset();
|
|
continue;
|
|
}
|
|
|
|
OpRWFlags rw_flags = i < op_count - 1 ? (OpRWFlags)rw_info.rwx[0] : (OpRWFlags)rw_info.rwx[1];
|
|
|
|
op._op_flags = rw_flags & ~(OpRWFlags::kZExt);
|
|
op._phys_id = Reg::kIdBad;
|
|
op._rm_size = 0;
|
|
op._reset_reserved();
|
|
|
|
uint64_t r_byte_mask = op.is_read() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
|
uint64_t w_byte_mask = op.is_write() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
|
|
|
op._read_byte_mask = r_byte_mask;
|
|
op._write_byte_mask = w_byte_mask;
|
|
op._extend_byte_mask = 0;
|
|
op._consecutive_lead_count = 0;
|
|
|
|
if (src_op.is_reg()) {
|
|
if (i == 0) {
|
|
op._consecutive_lead_count = uint8_t(op_count - 1);
|
|
}
|
|
else {
|
|
op.add_op_flags(OpRWFlags::kConsecutive);
|
|
}
|
|
}
|
|
else {
|
|
const Mem& mem_op = src_op.as<Mem>();
|
|
|
|
if (mem_op.has_base()) {
|
|
op.add_op_flags(OpRWFlags::kMemBaseRead);
|
|
if ((mem_op.has_index() || mem_op.has_offset()) && mem_op.is_pre_or_post()) {
|
|
op.add_op_flags(OpRWFlags::kMemBaseWrite);
|
|
}
|
|
}
|
|
|
|
if (mem_op.has_index()) {
|
|
op.add_op_flags(OpRWFlags::kMemIndexRead);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (uint32_t i = 0; i < op_count; i++) {
|
|
OpRWInfo& op = out->_operands[i];
|
|
const Operand_& src_op = operands[i];
|
|
|
|
if (!src_op.is_reg_or_mem()) {
|
|
op.reset();
|
|
continue;
|
|
}
|
|
|
|
OpRWFlags rw_flags = (OpRWFlags)rw_info.rwx[i];
|
|
|
|
op._op_flags = rw_flags & ~(OpRWFlags::kZExt);
|
|
op._phys_id = Reg::kIdBad;
|
|
op._rm_size = 0;
|
|
op._reset_reserved();
|
|
|
|
uint64_t r_byte_mask = op.is_read() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
|
uint64_t w_byte_mask = op.is_write() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
|
|
|
op._read_byte_mask = r_byte_mask;
|
|
op._write_byte_mask = w_byte_mask;
|
|
op._extend_byte_mask = 0;
|
|
op._consecutive_lead_count = 0;
|
|
|
|
if (src_op.is_reg()) {
|
|
if (src_op.as<Vec>().has_element_index()) {
|
|
// Only part of the vector is accessed if element index [] is used.
|
|
VecElementType element_type = src_op.as<Vec>().element_type();
|
|
uint32_t element_index = src_op.as<Vec>().element_index();
|
|
|
|
uint32_t element_size = element_type_size_table[size_t(element_type)];
|
|
uint64_t access_mask = uint64_t(Support::lsb_mask<uint32_t>(element_size)) << (element_index * element_size);
|
|
|
|
op._read_byte_mask &= access_mask;
|
|
op._write_byte_mask &= access_mask;
|
|
}
|
|
|
|
// TODO: [ARM] RW info is not finished.
|
|
}
|
|
else {
|
|
const Mem& mem_op = src_op.as<Mem>();
|
|
|
|
if (mem_op.has_base()) {
|
|
op.add_op_flags(OpRWFlags::kMemBaseRead);
|
|
if ((mem_op.has_index() || mem_op.has_offset()) && mem_op.is_pre_or_post()) {
|
|
op.add_op_flags(OpRWFlags::kMemBaseWrite);
|
|
}
|
|
}
|
|
|
|
if (mem_op.has_index()) {
|
|
op.add_op_flags(OpRWFlags::kMemIndexRead);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Error::kOk;
|
|
}
|
|
#endif // !ASMJIT_NO_INTROSPECTION
|
|
|
|
// a64::InstInternal - QueryFeatures
|
|
// =================================
|
|
|
|
#ifndef ASMJIT_NO_INTROSPECTION
|
|
Error query_features(const BaseInst& inst, const Operand_* operands, size_t op_count, CpuFeatures* out) noexcept {
|
|
// TODO: [ARM] QueryFeatures not implemented yet.
|
|
Support::maybe_unused(inst, operands, op_count, out);
|
|
return Error::kOk;
|
|
}
|
|
#endif // !ASMJIT_NO_INTROSPECTION
|
|
|
|
} // {InstInternal}
|
|
|
|
// a64::InstInternal - Unit
|
|
// ========================
|
|
|
|
#if defined(ASMJIT_TEST)
|
|
UNIT(arm_inst_api_text) {
|
|
// TODO:
|
|
}
|
|
#endif
|
|
|
|
ASMJIT_END_SUB_NAMESPACE
|
|
|
|
#endif // !ASMJIT_NO_AARCH64
|