// SPDX-License-Identifier: MIT #pragma once #include "Interface/Core/X86Tables/X86Tables.h" #include #include #include #include #include #include #include namespace FEXCore::Context { class ContextImpl; } namespace FEXCore::Frontend { class Decoder final { public: // New Frontend decoding struct DecodedBlocks final { uint64_t Entry {}; uint64_t NumInstructions {}; FEXCore::X86Tables::DecodedInst* DecodedInstructions; bool HasInvalidInstruction {}; }; struct DecodedBlockInformation final { uint64_t TotalInstructionCount; fextl::vector Blocks; }; Decoder(FEXCore::Context::ContextImpl* ctx); ~Decoder(); void DecodeInstructionsAtEntry(const uint8_t* InstStream, uint64_t PC, uint64_t MaxInst, std::function AddContainedCodePage); const DecodedBlockInformation* GetDecodedBlockInfo() const { return &BlockInfo; } uint64_t DecodedMinAddress {}; uint64_t DecodedMaxAddress {~0ULL}; void SetSectionMaxAddress(uint64_t v) { SectionMaxAddress = v; } void SetExternalBranches(fextl::set* v) { ExternalBranches = v; } void DelayedDisownBuffer() { PoolObject.DelayedDisownBuffer(); } private: // To pass any information from instruction prefixes // down into the actual instruction handling machinery. struct DecodedHeader { uint8_t vvvv; // Encoded operand in a VEX prefix. bool w; // VEX.W bit. bool L; // VEX.L bit (if set then 256 bit operation, if unset then scalar or 128-bit operation) }; FEXCore::Context::ContextImpl* CTX; const FEXCore::HLE::SyscallOSABI OSABI {}; bool DecodeInstruction(uint64_t PC); void BranchTargetInMultiblockRange(); bool BranchTargetCanContinue(bool FinalInstruction) const; uint8_t ReadByte(); uint8_t PeekByte(uint8_t Offset) const; uint64_t ReadData(uint8_t Size); void SkipBytes(uint8_t Size) { InstructionSize += Size; } bool NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op, DecodedHeader Options = {}); bool NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op); static constexpr size_t DefaultDecodedBufferSize = 0x10000; FEXCore::X86Tables::DecodedInst* DecodedBuffer {}; Utils::FixedSizePooledAllocation PoolObject; size_t DecodedSize {}; const uint8_t* InstStream; static constexpr size_t MAX_INST_SIZE = 15; uint8_t InstructionSize; std::array Instruction; FEXCore::X86Tables::DecodedInst* DecodeInst; // This is for multiblock data tracking bool SymbolAvailable {false}; uint64_t EntryPoint {}; uint64_t MaxCondBranchForward {}; uint64_t MaxCondBranchBackwards {~0ULL}; uint64_t SymbolMaxAddress {}; uint64_t SymbolMinAddress {~0ULL}; uint64_t SectionMaxAddress {~0ULL}; DecodedBlockInformation BlockInfo; fextl::set BlocksToDecode; fextl::set HasBlocks; fextl::set* ExternalBranches {nullptr}; // ModRM rm decoding using DecodeModRMPtr = void (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); void DecodeModRM_16(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); void DecodeModRM_64(X86Tables::DecodedOperand* Operand, X86Tables::ModRMDecoded ModRM); static constexpr std::array DecodeModRMs_Disp { &FEXCore::Frontend::Decoder::DecodeModRM_64, &FEXCore::Frontend::Decoder::DecodeModRM_16, }; const uint8_t* AdjustAddrForSpecialRegion(const uint8_t* _InstStream, uint64_t EntryPoint, uint64_t RIP); FEXCORE_TELEMETRY_INIT(VEXOpTelem, TYPE_USES_VEX_OPS); FEXCORE_TELEMETRY_INIT(EVEXOpTelem, TYPE_USES_EVEX_OPS); }; } // namespace FEXCore::Frontend