add support for JIT compilation
This commit is contained in:
278
lib/lepton/asmjit/arm/a64instapi.cpp
Normal file
278
lib/lepton/asmjit/arm/a64instapi.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
// This file is part of AsmJit project <https://asmjit.com>
|
||||
//
|
||||
// See asmjit.h or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
#include "../core/api-build_p.h"
|
||||
#if !defined(ASMJIT_NO_AARCH64)
|
||||
|
||||
#include "../core/cpuinfo.h"
|
||||
#include "../core/misc_p.h"
|
||||
#include "../core/support.h"
|
||||
#include "../arm/a64instapi_p.h"
|
||||
#include "../arm/a64instdb_p.h"
|
||||
#include "../arm/a64operand.h"
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
||||
|
||||
// a64::InstInternal - Text
|
||||
// ========================
|
||||
|
||||
#ifndef ASMJIT_NO_TEXT
|
||||
Error InstInternal::instIdToString(Arch arch, InstId instId, String& output) noexcept {
|
||||
uint32_t realId = instId & uint32_t(InstIdParts::kRealId);
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId)))
|
||||
return DebugUtils::errored(kErrorInvalidInstruction);
|
||||
|
||||
const InstDB::InstInfo& info = InstDB::infoById(realId);
|
||||
return output.append(InstDB::_nameData + info._nameDataIndex);
|
||||
}
|
||||
|
||||
InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!s))
|
||||
return Inst::kIdNone;
|
||||
|
||||
if (len == SIZE_MAX)
|
||||
len = strlen(s);
|
||||
|
||||
if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize))
|
||||
return Inst::kIdNone;
|
||||
|
||||
uint32_t prefix = uint32_t(s[0]) - 'a';
|
||||
if (ASMJIT_UNLIKELY(prefix > 'z' - 'a'))
|
||||
return Inst::kIdNone;
|
||||
|
||||
uint32_t index = InstDB::instNameIndex[prefix].start;
|
||||
if (ASMJIT_UNLIKELY(!index))
|
||||
return Inst::kIdNone;
|
||||
|
||||
const char* nameData = InstDB::_nameData;
|
||||
const InstDB::InstInfo* table = InstDB::_instInfoTable;
|
||||
|
||||
const InstDB::InstInfo* base = table + index;
|
||||
const InstDB::InstInfo* end = table + InstDB::instNameIndex[prefix].end;
|
||||
|
||||
for (size_t lim = (size_t)(end - base); lim != 0; lim >>= 1) {
|
||||
const InstDB::InstInfo* cur = base + (lim >> 1);
|
||||
int result = Support::cmpInstName(nameData + cur[0]._nameDataIndex, s, len);
|
||||
|
||||
if (result < 0) {
|
||||
base = cur + 1;
|
||||
lim--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result > 0)
|
||||
continue;
|
||||
|
||||
return uint32_t((size_t)(cur - table));
|
||||
}
|
||||
|
||||
return Inst::kIdNone;
|
||||
}
|
||||
#endif // !ASMJIT_NO_TEXT
|
||||
|
||||
// a64::InstInternal - Validate
|
||||
// ============================
|
||||
|
||||
#ifndef ASMJIT_NO_VALIDATION
|
||||
ASMJIT_FAVOR_SIZE Error InstInternal::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||
// TODO:
|
||||
DebugUtils::unused(arch, inst, operands, opCount, validationFlags);
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_NO_VALIDATION
|
||||
|
||||
// a64::InstInternal - QueryRWInfo
|
||||
// ===============================
|
||||
|
||||
#ifndef ASMJIT_NO_INTROSPECTION
|
||||
struct InstRWInfoData {
|
||||
uint8_t rwx[Globals::kMaxOpCount];
|
||||
};
|
||||
|
||||
static const InstRWInfoData instRWInfoData[] = {
|
||||
#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 elementTypeSize[8] = { 0, 1, 2, 4, 8, 4, 4, 0 };
|
||||
|
||||
Error InstInternal::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||
// Unused in Release configuration as the assert is not compiled in.
|
||||
DebugUtils::unused(arch);
|
||||
|
||||
// Only called when `arch` matches X86 family.
|
||||
ASMJIT_ASSERT(Environment::isFamilyARM(arch));
|
||||
|
||||
// Get the instruction data.
|
||||
uint32_t realId = inst.id() & uint32_t(InstIdParts::kRealId);
|
||||
|
||||
if (ASMJIT_UNLIKELY(!Inst::isDefinedId(realId)))
|
||||
return DebugUtils::errored(kErrorInvalidInstruction);
|
||||
|
||||
out->_instFlags = InstRWFlags::kNone;
|
||||
out->_opCount = uint8_t(opCount);
|
||||
out->_rmFeature = 0;
|
||||
out->_extraReg.reset();
|
||||
out->_readFlags = CpuRWFlags::kNone; // TODO: [ARM] Read PSTATUS.
|
||||
out->_writeFlags = CpuRWFlags::kNone; // TODO: [ARM] Write PSTATUS
|
||||
|
||||
const InstDB::InstInfo& instInfo = InstDB::_instInfoTable[realId];
|
||||
const InstRWInfoData& rwInfo = instRWInfoData[instInfo.rwInfoIndex()];
|
||||
|
||||
if (instInfo.hasFlag(InstDB::kInstFlagConsecutive) && opCount > 2) {
|
||||
for (uint32_t i = 0; i < opCount; i++) {
|
||||
OpRWInfo& op = out->_operands[i];
|
||||
const Operand_& srcOp = operands[i];
|
||||
|
||||
if (!srcOp.isRegOrMem()) {
|
||||
op.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
OpRWFlags rwFlags = i < opCount - 1 ? (OpRWFlags)rwInfo.rwx[0] : (OpRWFlags)rwInfo.rwx[1];
|
||||
|
||||
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
||||
op._physId = BaseReg::kIdBad;
|
||||
op._rmSize = 0;
|
||||
op._resetReserved();
|
||||
|
||||
uint64_t rByteMask = op.isRead() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
||||
uint64_t wByteMask = op.isWrite() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
||||
|
||||
op._readByteMask = rByteMask;
|
||||
op._writeByteMask = wByteMask;
|
||||
op._extendByteMask = 0;
|
||||
op._consecutiveLeadCount = 0;
|
||||
|
||||
if (srcOp.isReg()) {
|
||||
if (i == 0)
|
||||
op._consecutiveLeadCount = uint8_t(opCount - 1);
|
||||
else
|
||||
op.addOpFlags(OpRWFlags::kConsecutive);
|
||||
}
|
||||
else {
|
||||
const Mem& memOp = srcOp.as<Mem>();
|
||||
|
||||
if (memOp.hasBase()) {
|
||||
op.addOpFlags(OpRWFlags::kMemBaseRead);
|
||||
}
|
||||
|
||||
if (memOp.hasIndex()) {
|
||||
op.addOpFlags(OpRWFlags::kMemIndexRead);
|
||||
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexWrite : OpRWFlags::kNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < opCount; i++) {
|
||||
OpRWInfo& op = out->_operands[i];
|
||||
const Operand_& srcOp = operands[i];
|
||||
|
||||
if (!srcOp.isRegOrMem()) {
|
||||
op.reset();
|
||||
continue;
|
||||
}
|
||||
|
||||
OpRWFlags rwFlags = (OpRWFlags)rwInfo.rwx[i];
|
||||
|
||||
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
||||
op._physId = BaseReg::kIdBad;
|
||||
op._rmSize = 0;
|
||||
op._resetReserved();
|
||||
|
||||
uint64_t rByteMask = op.isRead() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
||||
uint64_t wByteMask = op.isWrite() ? 0xFFFFFFFFFFFFFFFFu : 0x0000000000000000u;
|
||||
|
||||
op._readByteMask = rByteMask;
|
||||
op._writeByteMask = wByteMask;
|
||||
op._extendByteMask = 0;
|
||||
op._consecutiveLeadCount = 0;
|
||||
|
||||
if (srcOp.isReg()) {
|
||||
if (srcOp.as<Vec>().hasElementIndex()) {
|
||||
// Only part of the vector is accessed if element index [] is used.
|
||||
uint32_t elementType = srcOp.as<Vec>().elementType();
|
||||
uint32_t elementIndex = srcOp.as<Vec>().elementIndex();
|
||||
|
||||
uint32_t elementSize = elementTypeSize[elementType];
|
||||
uint64_t accessMask = uint64_t(Support::lsbMask<uint32_t>(elementSize)) << (elementIndex * elementSize);
|
||||
|
||||
op._readByteMask &= accessMask;
|
||||
op._writeByteMask &= accessMask;
|
||||
}
|
||||
|
||||
// TODO: [ARM] RW info is not finished.
|
||||
}
|
||||
else {
|
||||
const Mem& memOp = srcOp.as<Mem>();
|
||||
|
||||
if (memOp.hasBase()) {
|
||||
op.addOpFlags(OpRWFlags::kMemBaseRead);
|
||||
}
|
||||
|
||||
if (memOp.hasIndex()) {
|
||||
op.addOpFlags(OpRWFlags::kMemIndexRead);
|
||||
op.addOpFlags(memOp.isPreOrPost() ? OpRWFlags::kMemIndexWrite : OpRWFlags::kNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_NO_INTROSPECTION
|
||||
|
||||
// a64::InstInternal - QueryFeatures
|
||||
// =================================
|
||||
|
||||
#ifndef ASMJIT_NO_INTROSPECTION
|
||||
Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
|
||||
// TODO: [ARM] QueryFeatures not implemented yet.
|
||||
DebugUtils::unused(arch, inst, operands, opCount, out);
|
||||
return kErrorOk;
|
||||
}
|
||||
#endif // !ASMJIT_NO_INTROSPECTION
|
||||
|
||||
// a64::InstInternal - Unit
|
||||
// ========================
|
||||
|
||||
#if defined(ASMJIT_TEST)
|
||||
UNIT(arm_inst_api_text) {
|
||||
// TODO:
|
||||
}
|
||||
#endif
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
#endif // !ASMJIT_NO_AARCH64
|
||||
Reference in New Issue
Block a user