// This file is part of AsmJit project // // 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_p.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); char nameData[32]; size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[realId], InstDB::_instNameStringTable); return output.append(nameData, nameSize); } InstId InstInternal::stringToInstId(Arch arch, const char* s, size_t len) noexcept { DebugUtils::unused(arch); if (ASMJIT_UNLIKELY(!s)) return Inst::kIdNone; if (len == SIZE_MAX) len = strlen(s); if (ASMJIT_UNLIKELY(len == 0 || len > InstDB::kMaxNameSize)) return Inst::kIdNone; uint32_t prefix = uint32_t(s[0]) - 'a'; if (ASMJIT_UNLIKELY(prefix > 'z' - 'a')) return Inst::kIdNone; size_t base = InstDB::instNameIndex[prefix].start; size_t end = InstDB::instNameIndex[prefix].end; if (ASMJIT_UNLIKELY(!base)) return Inst::kIdNone; char nameData[32]; for (size_t lim = end - base; lim != 0; lim >>= 1) { size_t instId = base + (lim >> 1); size_t nameSize = Support::decodeInstName(nameData, InstDB::_instNameIndexTable[instId], InstDB::_instNameStringTable); int result = Support::compareStringViews(s, len, nameData, nameSize); if (result < 0) continue; if (result > 0) { base = instId + 1; lim--; continue; } return InstId(instId); } return Inst::kIdNone; } #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(); 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().hasElementIndex()) { // Only part of the vector is accessed if element index [] is used. uint32_t elementType = srcOp.as().elementType(); uint32_t elementIndex = srcOp.as().elementIndex(); uint32_t elementSize = elementTypeSize[elementType]; uint64_t accessMask = uint64_t(Support::lsbMask(elementSize)) << (elementIndex * elementSize); op._readByteMask &= accessMask; op._writeByteMask &= accessMask; } // TODO: [ARM] RW info is not finished. } else { const Mem& memOp = srcOp.as(); 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