LCOV - code coverage report
Current view: top level - asmjit - x86instimpl.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 0 170 0.0 %
Date: 2024-10-11 08:09:49 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifdef __PLUMED_HAS_ASMJIT
      21             : #pragma GCC diagnostic push
      22             : #pragma GCC diagnostic ignored "-Wpedantic"
      23             : // [AsmJit]
      24             : // Complete x86/x64 JIT and Remote Assembler for C++.
      25             : //
      26             : // [License]
      27             : // Zlib - See LICENSE.md file in the package.
      28             : 
      29             : // [Export]
      30             : #define ASMJIT_EXPORTS
      31             : 
      32             : // [Dependencies]
      33             : #include "./misc_p.h"
      34             : #include "./utils.h"
      35             : #include "./x86instimpl_p.h"
      36             : #include "./x86operand.h"
      37             : 
      38             : // [Api-Begin]
      39             : #include "./asmjit_apibegin.h"
      40             : 
      41             : namespace PLMD {
      42             : namespace asmjit {
      43             : 
      44             : // ============================================================================
      45             : // [asmjit::X86InstImpl - Validate]
      46             : // ============================================================================
      47             : 
      48             : #if !defined(ASMJIT_DISABLE_VALIDATION)
      49             : template<uint32_t RegType>
      50             : struct X86OpTypeFromRegTypeT {
      51             :   enum {
      52             :     kValue = (RegType == X86Reg::kRegGpbLo) ? X86Inst::kOpGpbLo :
      53             :              (RegType == X86Reg::kRegGpbHi) ? X86Inst::kOpGpbHi :
      54             :              (RegType == X86Reg::kRegGpw  ) ? X86Inst::kOpGpw   :
      55             :              (RegType == X86Reg::kRegGpd  ) ? X86Inst::kOpGpd   :
      56             :              (RegType == X86Reg::kRegGpq  ) ? X86Inst::kOpGpq   :
      57             :              (RegType == X86Reg::kRegXmm  ) ? X86Inst::kOpXmm   :
      58             :              (RegType == X86Reg::kRegYmm  ) ? X86Inst::kOpYmm   :
      59             :              (RegType == X86Reg::kRegZmm  ) ? X86Inst::kOpZmm   :
      60             :              (RegType == X86Reg::kRegRip  ) ? X86Inst::kOpNone  :
      61             :              (RegType == X86Reg::kRegSeg  ) ? X86Inst::kOpSeg   :
      62             :              (RegType == X86Reg::kRegFp   ) ? X86Inst::kOpFp    :
      63             :              (RegType == X86Reg::kRegMm   ) ? X86Inst::kOpMm    :
      64             :              (RegType == X86Reg::kRegK    ) ? X86Inst::kOpK     :
      65             :              (RegType == X86Reg::kRegBnd  ) ? X86Inst::kOpBnd   :
      66             :              (RegType == X86Reg::kRegCr   ) ? X86Inst::kOpCr    :
      67             :              (RegType == X86Reg::kRegDr   ) ? X86Inst::kOpDr    : X86Inst::kOpNone
      68             :   };
      69             : };
      70             : 
      71             : template<uint32_t RegType>
      72             : struct X86RegMaskFromRegTypeT {
      73             :   enum {
      74             :     kMask = (RegType == X86Reg::kRegGpbLo) ? 0x0000000FU :
      75             :             (RegType == X86Reg::kRegGpbHi) ? 0x0000000FU :
      76             :             (RegType == X86Reg::kRegGpw  ) ? 0x000000FFU :
      77             :             (RegType == X86Reg::kRegGpd  ) ? 0x000000FFU :
      78             :             (RegType == X86Reg::kRegGpq  ) ? 0x000000FFU :
      79             :             (RegType == X86Reg::kRegXmm  ) ? 0x000000FFU :
      80             :             (RegType == X86Reg::kRegYmm  ) ? 0x000000FFU :
      81             :             (RegType == X86Reg::kRegZmm  ) ? 0x000000FFU :
      82             :             (RegType == X86Reg::kRegRip  ) ? 0x00000001U :
      83             :             (RegType == X86Reg::kRegSeg  ) ? 0x0000007EU : // [ES|CS|SS|DS|FS|GS]
      84             :             (RegType == X86Reg::kRegFp   ) ? 0x000000FFU :
      85             :             (RegType == X86Reg::kRegMm   ) ? 0x000000FFU :
      86             :             (RegType == X86Reg::kRegK    ) ? 0x000000FFU :
      87             :             (RegType == X86Reg::kRegBnd  ) ? 0x0000000FU :
      88             :             (RegType == X86Reg::kRegCr   ) ? 0x0000FFFFU :
      89             :             (RegType == X86Reg::kRegDr   ) ? 0x000000FFU : X86Inst::kOpNone
      90             :   };
      91             : };
      92             : 
      93             : template<uint32_t RegType>
      94             : struct X64RegMaskFromRegTypeT {
      95             :   enum {
      96             :     kMask = (RegType == X86Reg::kRegGpbLo) ? 0x0000FFFFU :
      97             :             (RegType == X86Reg::kRegGpbHi) ? 0x0000000FU :
      98             :             (RegType == X86Reg::kRegGpw  ) ? 0x0000FFFFU :
      99             :             (RegType == X86Reg::kRegGpd  ) ? 0x0000FFFFU :
     100             :             (RegType == X86Reg::kRegGpq  ) ? 0x0000FFFFU :
     101             :             (RegType == X86Reg::kRegXmm  ) ? 0xFFFFFFFFU :
     102             :             (RegType == X86Reg::kRegYmm  ) ? 0xFFFFFFFFU :
     103             :             (RegType == X86Reg::kRegZmm  ) ? 0xFFFFFFFFU :
     104             :             (RegType == X86Reg::kRegRip  ) ? 0x00000001U :
     105             :             (RegType == X86Reg::kRegSeg  ) ? 0x0000007EU : // [ES|CS|SS|DS|FS|GS]
     106             :             (RegType == X86Reg::kRegFp   ) ? 0x000000FFU :
     107             :             (RegType == X86Reg::kRegMm   ) ? 0x000000FFU :
     108             :             (RegType == X86Reg::kRegK    ) ? 0x000000FFU :
     109             :             (RegType == X86Reg::kRegBnd  ) ? 0x0000000FU :
     110             :             (RegType == X86Reg::kRegCr   ) ? 0x0000FFFFU :
     111             :             (RegType == X86Reg::kRegDr   ) ? 0x0000FFFFU : X86Inst::kOpNone
     112             :   };
     113             : };
     114             : 
     115             : struct X86ValidationData {
     116             :   //! Allowed registers by reg-type (X86::kReg...).
     117             :   uint32_t allowedRegMask[X86Reg::kRegMax + 1];
     118             :   uint32_t allowedMemBaseRegs;
     119             :   uint32_t allowedMemIndexRegs;
     120             : };
     121             : 
     122             : static const uint32_t _x86OpFlagFromRegType[X86Reg::kRegMax + 1] = {
     123             :   ASMJIT_TABLE_T_32(X86OpTypeFromRegTypeT, kValue, 0)
     124             : };
     125             : 
     126             : static const X86ValidationData _x86ValidationData = {
     127             :   { ASMJIT_TABLE_T_32(X86RegMaskFromRegTypeT, kMask, 0) },
     128             :   (1U << X86Reg::kRegGpw) | (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegRip) | (1U << Label::kLabelTag),
     129             :   (1U << X86Reg::kRegGpw) | (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegXmm) | (1U << X86Reg::kRegYmm) | (1U << X86Reg::kRegZmm)
     130             : };
     131             : 
     132             : static const X86ValidationData _x64ValidationData = {
     133             :   { ASMJIT_TABLE_T_32(X64RegMaskFromRegTypeT, kMask, 0) },
     134             :   (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegGpq) | (1U << X86Reg::kRegRip) | (1U << Label::kLabelTag),
     135             :   (1U << X86Reg::kRegGpd) | (1U << X86Reg::kRegGpq) | (1U << X86Reg::kRegXmm) | (1U << X86Reg::kRegYmm) | (1U << X86Reg::kRegZmm)
     136             : };
     137             : 
     138             : static ASMJIT_INLINE bool x86CheckOSig(const X86Inst::OSignature& op, const X86Inst::OSignature& ref, bool& immOutOfRange) noexcept {
     139             :   // Fail if operand types are incompatible.
     140           0 :   uint32_t opFlags = op.flags;
     141           0 :   if ((opFlags & ref.flags) == 0) {
     142             :     // Mark temporarily `immOutOfRange` so we can return a more descriptive error.
     143           0 :     if ((opFlags & X86Inst::kOpAllImm) && (ref.flags & X86Inst::kOpAllImm)) {
     144             :       immOutOfRange = true;
     145           0 :       return true;
     146             :     }
     147             : 
     148             :     return false;
     149             :   }
     150             : 
     151             :   // Fail if memory specific flags and sizes are incompatibles.
     152           0 :   uint32_t opMemFlags = op.memFlags;
     153           0 :   if (opMemFlags != 0) {
     154           0 :     uint32_t refMemFlags = ref.memFlags;
     155           0 :     if ((refMemFlags & opMemFlags) == 0)
     156             :       return false;
     157             : 
     158           0 :     if ((refMemFlags & X86Inst::kMemOpBaseOnly) && !(opMemFlags & X86Inst::kMemOpBaseOnly))
     159             :       return false;
     160             :   }
     161             : 
     162             :   // Specific register index.
     163           0 :   if (opFlags & X86Inst::kOpAllRegs) {
     164           0 :     uint32_t refRegMask = ref.regMask;
     165           0 :     if (refRegMask && !(op.regMask & refRegMask))
     166           0 :       return false;
     167             :   }
     168             : 
     169             :   return true;
     170             : }
     171             : 
     172           0 : ASMJIT_FAVOR_SIZE Error X86InstImpl::validate(uint32_t archType, const Inst::Detail& detail, const Operand_* operands, uint32_t count) noexcept {
     173             :   uint32_t i;
     174             :   uint32_t archMask;
     175             :   const X86ValidationData* vd;
     176             : 
     177           0 :   if (!ArchInfo::isX86Family(archType))
     178             :     return DebugUtils::errored(kErrorInvalidArch);
     179             : 
     180           0 :   if (archType == ArchInfo::kTypeX86) {
     181             :     vd = &_x86ValidationData;
     182             :     archMask = X86Inst::kArchMaskX86;
     183             :   }
     184             :   else {
     185             :     vd = &_x64ValidationData;
     186             :     archMask = X86Inst::kArchMaskX64;
     187             :   }
     188             : 
     189             :   // Get the instruction data.
     190           0 :   uint32_t instId = detail.instId;
     191           0 :   uint32_t options = detail.options;
     192             : 
     193           0 :   if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount))
     194             :     return DebugUtils::errored(kErrorInvalidArgument);
     195             : 
     196             :   const X86Inst* iData = &X86InstDB::instData[instId];
     197             :   uint32_t iFlags = iData->getFlags();
     198             : 
     199             :   // Validate LOCK, XACQUIRE, and XRELEASE prefixes.
     200             :   const uint32_t kLockXAcqRel = X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease;
     201           0 :   if (options & (X86Inst::kOptionLock | kLockXAcqRel)) {
     202           0 :     if (options & X86Inst::kOptionLock) {
     203           0 :       if (ASMJIT_UNLIKELY(!(iFlags & X86Inst::kFlagLock) && !(options & kLockXAcqRel)))
     204             :         return DebugUtils::errored(kErrorInvalidLockPrefix);
     205             : 
     206           0 :       if (ASMJIT_UNLIKELY(count < 1 || !operands[0].isMem()))
     207             :         return DebugUtils::errored(kErrorInvalidLockPrefix);
     208             :     }
     209             : 
     210           0 :     if (options & kLockXAcqRel) {
     211           0 :       if (ASMJIT_UNLIKELY(!(options & X86Inst::kOptionLock) || (options & kLockXAcqRel) == kLockXAcqRel))
     212             :         return DebugUtils::errored(kErrorInvalidPrefixCombination);
     213             : 
     214           0 :       if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXAcquire) && !(iFlags & X86Inst::kFlagXAcquire)))
     215             :         return DebugUtils::errored(kErrorInvalidXAcquirePrefix);
     216             : 
     217           0 :       if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXRelease) && !(iFlags & X86Inst::kFlagXRelease)))
     218             :         return DebugUtils::errored(kErrorInvalidXReleasePrefix);
     219             :     }
     220             :   }
     221             : 
     222             :   // Validate REP and REPNZ prefixes.
     223             :   const uint32_t kRepRepRepnz = X86Inst::kOptionRep | X86Inst::kOptionRepnz;
     224           0 :   if (options & kRepRepRepnz) {
     225           0 :     if (ASMJIT_UNLIKELY((options & kRepRepRepnz) == kRepRepRepnz))
     226             :       return DebugUtils::errored(kErrorInvalidPrefixCombination);
     227             : 
     228           0 :     if (ASMJIT_UNLIKELY((options & X86Inst::kOptionRep) && !(iFlags & X86Inst::kFlagRep)))
     229             :       return DebugUtils::errored(kErrorInvalidRepPrefix);
     230             : 
     231           0 :     if (ASMJIT_UNLIKELY((options & X86Inst::kOptionRepnz) && !(iFlags & X86Inst::kFlagRepnz)))
     232             :       return DebugUtils::errored(kErrorInvalidRepPrefix);
     233             : 
     234             :     // TODO: Validate extraReg {cx|ecx|rcx}.
     235             :   }
     236             : 
     237             :   // Translate the given operands to `X86Inst::OSignature`.
     238             :   X86Inst::OSignature oSigTranslated[6];
     239             :   uint32_t combinedOpFlags = 0;
     240             :   uint32_t combinedRegMask = 0;
     241             : 
     242             :   const X86Mem* memOp = nullptr;
     243             : 
     244           0 :   for (i = 0; i < count; i++) {
     245           0 :     const Operand_& op = operands[i];
     246           0 :     if (op.getOp() == Operand::kOpNone) break;
     247             : 
     248             :     uint32_t opFlags = 0;
     249             :     uint32_t memFlags = 0;
     250             :     uint32_t regMask = 0;
     251             : 
     252           0 :     switch (op.getOp()) {
     253             :       case Operand::kOpReg: {
     254             :         uint32_t regType = op.as<Reg>().getType();
     255           0 :         if (ASMJIT_UNLIKELY(regType >= X86Reg::kRegCount))
     256             :           return DebugUtils::errored(kErrorInvalidRegType);
     257             : 
     258           0 :         opFlags = _x86OpFlagFromRegType[regType];
     259           0 :         if (ASMJIT_UNLIKELY(opFlags == 0))
     260             :           return DebugUtils::errored(kErrorInvalidRegType);
     261             : 
     262             :         // If `regId` is equal or greater than Operand::kPackedIdMin it means
     263             :         // that the register is virtual and its index will be assigned later
     264             :         // by the register allocator. We must pass unless asked to disallow
     265             :         // virtual registers.
     266             :         // TODO: We need an option to refuse virtual regs here.
     267             :         uint32_t regId = op.getId();
     268           0 :         if (regId < Operand::kPackedIdMin) {
     269           0 :           if (ASMJIT_UNLIKELY(regId >= 32))
     270             :             return DebugUtils::errored(kErrorInvalidPhysId);
     271             : 
     272             :           regMask = Utils::mask(regId);
     273           0 :           if (ASMJIT_UNLIKELY((vd->allowedRegMask[regType] & regMask) == 0))
     274             :             return DebugUtils::errored(kErrorInvalidPhysId);
     275             : 
     276           0 :           combinedRegMask |= regMask;
     277             :         }
     278             :         else {
     279             :           regMask = 0xFFFFFFFFU;
     280             :         }
     281             :         break;
     282             :       }
     283             : 
     284             :       // TODO: Validate base and index and combine with `combinedRegMask`.
     285             :       case Operand::kOpMem: {
     286             :         const X86Mem& m = op.as<X86Mem>();
     287             : 
     288             :         uint32_t baseType = m.getBaseType();
     289             :         uint32_t indexType = m.getIndexType();
     290             : 
     291             :         memOp = &m;
     292             : 
     293           0 :         if (m.getSegmentId() > 6)
     294             :           return DebugUtils::errored(kErrorInvalidSegment);
     295             : 
     296           0 :         if (baseType) {
     297             :           uint32_t baseId = m.getBaseId();
     298             : 
     299           0 :           if (m.isRegHome()) {
     300             :             // Home address of virtual register. In such case we don't want to
     301             :             // validate the type of the base register as it will always be patched
     302             :             // to ESP|RSP.
     303             :           }
     304             :           else {
     305           0 :             if (ASMJIT_UNLIKELY((vd->allowedMemBaseRegs & (1U << baseType)) == 0))
     306             :               return DebugUtils::errored(kErrorInvalidAddress);
     307             :           }
     308             : 
     309             :           // Create information that will be validated only if this is an implicit
     310             :           // memory operand. Basically only usable for string instructions and other
     311             :           // instructions where memory operand is implicit and has 'seg:[reg]' form.
     312           0 :           if (baseId < Operand::kPackedIdMin) {
     313             :             // Physical base id.
     314             :             regMask = Utils::mask(baseId);
     315           0 :             combinedRegMask |= regMask;
     316             :           }
     317             :           else {
     318             :             // Virtual base id - will the whole mask for implicit mem validation.
     319             :             // The register is not assigned yet, so we cannot predict the phys id.
     320             :             regMask = 0xFFFFFFFFU;
     321             :           }
     322             : 
     323           0 :           if (!indexType && !m.getOffsetLo32())
     324             :             memFlags |= X86Inst::kMemOpBaseOnly;
     325             :         }
     326             :         else {
     327             :           // Base is an address, make sure that the address doesn't overflow 32-bit
     328             :           // integer (either int32_t or uint32_t) in 32-bit targets.
     329             :           int64_t offset = m.getOffset();
     330           0 :           if (archMask == X86Inst::kArchMaskX86 && !Utils::isInt32(offset) && !Utils::isUInt32(offset))
     331             :             return DebugUtils::errored(kErrorInvalidAddress);
     332             :         }
     333             : 
     334           0 :         if (indexType) {
     335           0 :           if (ASMJIT_UNLIKELY((vd->allowedMemIndexRegs & (1U << indexType)) == 0))
     336             :             return DebugUtils::errored(kErrorInvalidAddress);
     337             : 
     338           0 :           if (indexType == X86Reg::kRegXmm) {
     339             :             opFlags |= X86Inst::kOpVm;
     340           0 :             memFlags |= X86Inst::kMemOpVm32x | X86Inst::kMemOpVm64x;
     341             :           }
     342           0 :           else if (indexType == X86Reg::kRegYmm) {
     343             :             opFlags |= X86Inst::kOpVm;
     344           0 :             memFlags |= X86Inst::kMemOpVm32y | X86Inst::kMemOpVm64y;
     345             :           }
     346           0 :           else if (indexType == X86Reg::kRegZmm) {
     347             :             opFlags |= X86Inst::kOpVm;
     348           0 :             memFlags |= X86Inst::kMemOpVm32z | X86Inst::kMemOpVm64z;
     349             :           }
     350             :           else {
     351             :             opFlags |= X86Inst::kOpMem;
     352           0 :             if (baseType)
     353           0 :               memFlags |= X86Inst::kMemOpMib;
     354             :           }
     355             : 
     356             :           // [RIP + {XMM|YMM|ZMM}] is not allowed.
     357           0 :           if (baseType == X86Reg::kRegRip && (opFlags & X86Inst::kOpVm))
     358             :             return DebugUtils::errored(kErrorInvalidAddress);
     359             : 
     360             :           uint32_t indexId = m.getIndexId();
     361           0 :           if (indexId < Operand::kPackedIdMin)
     362           0 :             combinedRegMask |= Utils::mask(indexId);
     363             : 
     364             :           // Only used for implicit memory operands having 'seg:[reg]' form, so clear it.
     365             :           regMask = 0;
     366             :         }
     367             :         else {
     368             :           opFlags |= X86Inst::kOpMem;
     369             :         }
     370             : 
     371             :         switch (m.getSize()) {
     372           0 :           case  0: memFlags |= X86Inst::kMemOpAny ; break;
     373           0 :           case  1: memFlags |= X86Inst::kMemOpM8  ; break;
     374           0 :           case  2: memFlags |= X86Inst::kMemOpM16 ; break;
     375           0 :           case  4: memFlags |= X86Inst::kMemOpM32 ; break;
     376           0 :           case  6: memFlags |= X86Inst::kMemOpM48 ; break;
     377           0 :           case  8: memFlags |= X86Inst::kMemOpM64 ; break;
     378           0 :           case 10: memFlags |= X86Inst::kMemOpM80 ; break;
     379           0 :           case 16: memFlags |= X86Inst::kMemOpM128; break;
     380           0 :           case 32: memFlags |= X86Inst::kMemOpM256; break;
     381           0 :           case 64: memFlags |= X86Inst::kMemOpM512; break;
     382             :           default:
     383             :             return DebugUtils::errored(kErrorInvalidOperandSize);
     384             :         }
     385             : 
     386             :         break;
     387             :       }
     388             : 
     389             :       case Operand::kOpImm: {
     390             :         uint64_t immValue = op.as<Imm>().getUInt64();
     391             :         uint32_t immFlags = 0;
     392             : 
     393           0 :         if (static_cast<int64_t>(immValue) >= 0) {
     394             :           const uint32_t k32AndMore = X86Inst::kOpI32 | X86Inst::kOpU32 |
     395             :                                       X86Inst::kOpI64 | X86Inst::kOpU64 ;
     396             : 
     397           0 :           if (immValue <= 0xFU)
     398             :             immFlags = X86Inst::kOpU4 | X86Inst::kOpI8 | X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
     399           0 :           else if (immValue <= 0x7FU)
     400             :             immFlags = X86Inst::kOpI8 | X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
     401           0 :           else if (immValue <= 0xFFU)
     402             :             immFlags = X86Inst::kOpU8 | X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
     403           0 :           else if (immValue <= 0x7FFFU)
     404             :             immFlags = X86Inst::kOpI16 | X86Inst::kOpU16 | k32AndMore;
     405           0 :           else if (immValue <= 0xFFFFU)
     406             :             immFlags = X86Inst::kOpU16 | k32AndMore;
     407           0 :           else if (immValue <= 0x7FFFFFFFU)
     408             :             immFlags = k32AndMore;
     409           0 :           else if (immValue <= 0xFFFFFFFFU)
     410             :             immFlags = X86Inst::kOpU32 | X86Inst::kOpI64 | X86Inst::kOpU64;
     411             :           else if (immValue <= ASMJIT_UINT64_C(0x7FFFFFFFFFFFFFFF))
     412             :             immFlags = X86Inst::kOpI64 | X86Inst::kOpU64;
     413             :           else
     414             :             immFlags = X86Inst::kOpU64;
     415             :         }
     416             :         else {
     417             :           // 2s complement negation, as our number is unsigned...
     418           0 :           immValue = (~immValue + 1);
     419             : 
     420           0 :           if (immValue <= 0x80U)
     421             :             immFlags = X86Inst::kOpI8 | X86Inst::kOpI16 | X86Inst::kOpI32 | X86Inst::kOpI64;
     422           0 :           else if (immValue <= 0x8000U)
     423             :             immFlags = X86Inst::kOpI16 | X86Inst::kOpI32 | X86Inst::kOpI64;
     424           0 :           else if (immValue <= 0x80000000U)
     425             :             immFlags = X86Inst::kOpI32 | X86Inst::kOpI64;
     426             :           else
     427             :             immFlags = X86Inst::kOpI64;
     428             :         }
     429             :         opFlags |= immFlags;
     430             :         break;
     431             :       }
     432             : 
     433             :       case Operand::kOpLabel: {
     434             :         opFlags |= X86Inst::kOpRel8 | X86Inst::kOpRel32;
     435             :         break;
     436             :       }
     437             : 
     438             :       default:
     439             :         return DebugUtils::errored(kErrorInvalidState);
     440             :     }
     441             : 
     442             :     X86Inst::OSignature& tod = oSigTranslated[i];
     443           0 :     tod.flags = opFlags;
     444           0 :     tod.memFlags = static_cast<uint16_t>(memFlags);
     445           0 :     tod.regMask = static_cast<uint8_t>(regMask & 0xFFU);
     446           0 :     combinedOpFlags |= opFlags;
     447             :   }
     448             : 
     449             :   // Decrease the number of operands of those that are none. This is important
     450             :   // as Assembler and CodeCompiler may just pass more operands where some of
     451             :   // them are none (it means that no operand is given at that index). However,
     452             :   // validate that there are no gaps (like [reg, none, reg] or [none, reg]).
     453           0 :   if (i < count) {
     454           0 :     while (--count > i)
     455           0 :       if (ASMJIT_UNLIKELY(!operands[count].isNone()))
     456             :         return DebugUtils::errored(kErrorInvalidState);
     457             :   }
     458             : 
     459             :   // Validate X86 and X64 specific cases.
     460           0 :   if (archMask == X86Inst::kArchMaskX86) {
     461             :     // Illegal use of 64-bit register in 32-bit mode.
     462           0 :     if (ASMJIT_UNLIKELY((combinedOpFlags & X86Inst::kOpGpq) != 0))
     463             :       return DebugUtils::errored(kErrorInvalidUseOfGpq);
     464             :   }
     465             :   else {
     466             :     // Illegal use of a high 8-bit register with REX prefix.
     467           0 :     if (ASMJIT_UNLIKELY((combinedOpFlags & X86Inst::kOpGpbHi) != 0 && (combinedRegMask & 0xFFFFFF00U) != 0))
     468             :       return DebugUtils::errored(kErrorInvalidUseOfGpbHi);
     469             :   }
     470             : 
     471             :   // Validate instruction operands.
     472             :   const X86Inst::CommonData* commonData = &iData->getCommonData();
     473           0 :   const X86Inst::ISignature* iSig = X86InstDB::iSignatureData + commonData->_iSignatureIndex;
     474           0 :   const X86Inst::ISignature* iEnd = iSig                      + commonData->_iSignatureCount;
     475             : 
     476           0 :   if (iSig != iEnd) {
     477             :     const X86Inst::OSignature* oSigData = X86InstDB::oSignatureData;
     478             : 
     479             :     // If set it means that we matched a signature where only immediate value
     480             :     // was out of bounds. We can return a more descriptive error if we know this.
     481             :     bool globalImmOutOfRange = false;
     482             : 
     483             :     do {
     484             :       // Check if the architecture is compatible.
     485           0 :       if ((iSig->archMask & archMask) == 0) continue;
     486             : 
     487             :       // Compare the operands table with reference operands.
     488             :       uint32_t j = 0;
     489           0 :       uint32_t iSigCount = iSig->opCount;
     490             :       bool localImmOutOfRange = false;
     491             : 
     492           0 :       if (iSigCount == count) {
     493           0 :         for (j = 0; j < count; j++)
     494           0 :           if (!x86CheckOSig(oSigTranslated[j], oSigData[iSig->operands[j]], localImmOutOfRange))
     495             :             break;
     496             :       }
     497           0 :       else if (iSigCount - iSig->implicit == count) {
     498             :         uint32_t r = 0;
     499           0 :         for (j = 0; j < count && r < iSigCount; j++, r++) {
     500           0 :           const X86Inst::OSignature* oChk = oSigTranslated + j;
     501             :           const X86Inst::OSignature* oRef;
     502           0 : Next:
     503           0 :           oRef = oSigData + iSig->operands[r];
     504             :           // Skip implicit.
     505           0 :           if ((oRef->flags & X86Inst::kOpImplicit) != 0) {
     506           0 :             if (++r >= iSigCount)
     507             :               break;
     508             :             else
     509           0 :               goto Next;
     510             :           }
     511             : 
     512           0 :           if (!x86CheckOSig(*oChk, *oRef, localImmOutOfRange))
     513             :             break;
     514             :         }
     515             :       }
     516             : 
     517           0 :       if (j == count) {
     518           0 :         if (!localImmOutOfRange) {
     519             :           // Match, must clear possible `globalImmOutOfRange`.
     520             :           globalImmOutOfRange = false;
     521             :           break;
     522             :         }
     523             :         globalImmOutOfRange = localImmOutOfRange;
     524             :       }
     525           0 :     } while (++iSig != iEnd);
     526             : 
     527           0 :     if (iSig == iEnd) {
     528           0 :       if (globalImmOutOfRange)
     529             :         return DebugUtils::errored(kErrorInvalidImmediate);
     530             :       else
     531           0 :         return DebugUtils::errored(kErrorInvalidInstruction);
     532             :     }
     533             :   }
     534             : 
     535             :   // Validate AVX-512 options:
     536             :   const RegOnly& extraReg = detail.extraReg;
     537             :   const uint32_t kAvx512Options = X86Inst::kOptionZMask   |
     538             :                                   X86Inst::kOption1ToX    |
     539             :                                   X86Inst::kOptionER      |
     540             :                                   X86Inst::kOptionSAE     ;
     541             : 
     542           0 :   if (!extraReg.isNone() || (options & kAvx512Options)) {
     543           0 :     if (commonData->hasFlag(X86Inst::kFlagEvex)) {
     544             :       // Validate AVX-512 {k} and {k}{z}.
     545           0 :       if (!extraReg.isNone()) {
     546             :         // Mask can only be specified by a 'k' register.
     547           0 :         if (ASMJIT_UNLIKELY(extraReg.getType() != X86Reg::kRegK))
     548             :           return DebugUtils::errored(kErrorInvalidKMaskReg);
     549             : 
     550           0 :         if (ASMJIT_UNLIKELY(!commonData->hasAvx512K()))
     551             :           return DebugUtils::errored(kErrorInvalidKMaskUse);
     552             :       }
     553             : 
     554           0 :       if ((options & X86Inst::kOptionZMask)) {
     555           0 :         if (ASMJIT_UNLIKELY((options & X86Inst::kOptionZMask) != 0 && !commonData->hasAvx512Z()))
     556             :           return DebugUtils::errored(kErrorInvalidKZeroUse);
     557             :       }
     558             : 
     559             :       // Validate AVX-512 broadcast {1tox}.
     560           0 :       if (options & X86Inst::kOption1ToX) {
     561           0 :         if (ASMJIT_UNLIKELY(!memOp))
     562             :           return DebugUtils::errored(kErrorInvalidBroadcast);
     563             : 
     564             :         uint32_t size = memOp->getSize();
     565           0 :         if (size != 0) {
     566             :           // The the size is specified it has to match the broadcast size.
     567           0 :           if (ASMJIT_UNLIKELY(commonData->hasAvx512B32() && size != 4))
     568             :             return DebugUtils::errored(kErrorInvalidBroadcast);
     569             : 
     570           0 :           if (ASMJIT_UNLIKELY(commonData->hasAvx512B64() && size != 8))
     571             :             return DebugUtils::errored(kErrorInvalidBroadcast);
     572             :         }
     573             :       }
     574             : 
     575             :       // Validate AVX-512 {sae} and {er}.
     576           0 :       if (options & (X86Inst::kOptionSAE | X86Inst::kOptionER)) {
     577             :         // Rounding control is impossible if the instruction is not reg-to-reg.
     578           0 :         if (ASMJIT_UNLIKELY(memOp))
     579             :           return DebugUtils::errored(kErrorInvalidEROrSAE);
     580             : 
     581             :         // Check if {sae} or {er} is supported by the instruction.
     582           0 :         if (options & X86Inst::kOptionER) {
     583             :           // NOTE: if both {sae} and {er} are set, we don't care, as {sae} is implied.
     584           0 :           if (ASMJIT_UNLIKELY(!commonData->hasAvx512ER()))
     585             :             return DebugUtils::errored(kErrorInvalidEROrSAE);
     586             : 
     587             :           // {er} is defined for scalar ops or vector ops using zmm (LL = 10). We
     588             :           // don't need any more bits in the instruction database to be able to
     589             :           // validate this, as each AVX512 instruction that has broadcast is vector
     590             :           // instruction (in this case we require zmm registers), otherwise it's a
     591             :           // scalar instruction, which is valid.
     592           0 :           if (commonData->hasAvx512B()) {
     593             :             // Supports broadcast, thus we require LL to be '10', which means there
     594             :             // have to be zmm registers used. We don't calculate LL here, but we know
     595             :             // that it would be '10' if there is at least one ZMM register used.
     596             : 
     597             :             // There is no 'ER' enabled instruction with less than two operands.
     598             :             ASMJIT_ASSERT(count >= 2);
     599           0 :             if (ASMJIT_UNLIKELY(!X86Reg::isZmm(operands[0]) && !X86Reg::isZmm(operands[1])))
     600             :               return DebugUtils::errored(kErrorInvalidEROrSAE);
     601             :           }
     602             :         }
     603             :         else {
     604             :           // {sae} doesn't have the same limitations as {er}, this is enough.
     605           0 :           if (ASMJIT_UNLIKELY(!commonData->hasAvx512SAE()))
     606             :             return DebugUtils::errored(kErrorInvalidEROrSAE);
     607             :         }
     608             :       }
     609             :     }
     610             :     else {
     611             :       // Not AVX512 instruction - maybe OpExtra is xCX register used by REP/REPNZ prefix. Otherwise the instruction is invalid.
     612           0 :       if ((options & kAvx512Options) || (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) == 0)
     613             :         return DebugUtils::errored(kErrorInvalidInstruction);
     614             :     }
     615             :   }
     616             : 
     617             :   return kErrorOk;
     618             : }
     619             : #endif
     620             : 
     621             : // ============================================================================
     622             : // [asmjit::X86InstImpl - CheckFeatures]
     623             : // ============================================================================
     624             : 
     625             : #if !defined(ASMJIT_DISABLE_EXTENSIONS)
     626           0 : ASMJIT_FAVOR_SIZE static uint32_t x86GetRegTypesMask(const Operand_* operands, uint32_t count) noexcept {
     627             :   uint32_t mask = 0;
     628           0 :   for (uint32_t i = 0; i < count; i++) {
     629           0 :     const Operand_& op = operands[i];
     630           0 :     if (op.isReg()) {
     631             :       const Reg& reg = op.as<Reg>();
     632           0 :       mask |= Utils::mask(reg.getType());
     633             :     }
     634           0 :     else if (op.isMem()) {
     635             :       const Mem& mem = op.as<Mem>();
     636           0 :       if (mem.hasBaseReg()) mask |= Utils::mask(mem.getBaseType());
     637           0 :       if (mem.hasIndexReg()) mask |= Utils::mask(mem.getIndexType());
     638             :     }
     639             :   }
     640           0 :   return mask;
     641             : }
     642             : 
     643           0 : ASMJIT_FAVOR_SIZE Error X86InstImpl::checkFeatures(uint32_t archType, const Inst::Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept {
     644           0 :   if (!ArchInfo::isX86Family(archType))
     645             :     return DebugUtils::errored(kErrorInvalidArch);
     646             : 
     647             :   // Get the instruction data.
     648           0 :   uint32_t instId = detail.instId;
     649           0 :   if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount))
     650             :     return DebugUtils::errored(kErrorInvalidArgument);
     651             : 
     652             :   const X86Inst* iData = &X86InstDB::instData[instId];
     653             :   const X86Inst::OperationData& od = iData->getOperationData();
     654             : 
     655             :   const uint8_t* fData = od.getFeaturesData();
     656             :   const uint8_t* fEnd = od.getFeaturesEnd();
     657             : 
     658             :   // Copy all features to `out`.
     659             :   out.reset();
     660             :   do {
     661           0 :     uint32_t feature = fData[0];
     662           0 :     if (!feature)
     663             :       break;
     664             :     out.add(feature);
     665           0 :   } while (++fData != fEnd);
     666             : 
     667             :   // Since AsmJit merges all instructions that share the same name we have to
     668             :   // deal with some special cases and also with MMX/SSE and AVX/AVX2 overlaps.
     669             : 
     670             :   // Only proceed if there were some CPU flags set.
     671           0 :   if (fData != od.getFeaturesData()) {
     672           0 :     uint32_t mask = x86GetRegTypesMask(operands, count);
     673             : 
     674             :     // Check for MMX vs SSE overlap.
     675           0 :     if (out.has(CpuInfo::kX86FeatureMMX) || out.has(CpuInfo::kX86FeatureMMX2)) {
     676             :       // Only instructions defined by SSE and SSE2 overlap. Instructions introduced
     677             :       // by newer instruction sets like SSE3+ don't state MMX as they require SSE3+.
     678           0 :       if (out.has(CpuInfo::kX86FeatureSSE) || out.has(CpuInfo::kX86FeatureSSE2)) {
     679           0 :         if (!(mask & Utils::mask(X86Reg::kRegXmm))) {
     680             :           // The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only.
     681             :           out.remove(CpuInfo::kX86FeatureSSE);
     682             :           out.remove(CpuInfo::kX86FeatureSSE2);
     683             :         }
     684             :         else {
     685             :           out.remove(CpuInfo::kX86FeatureMMX);
     686             :           out.remove(CpuInfo::kX86FeatureMMX2);
     687             :         }
     688             : 
     689             :         // Special case: PEXTRW instruction is MMX/SSE2 instruction. However, this
     690             :         // instruction couldn't access memory (only register to register extract) so
     691             :         // when SSE4.1 introduced the whole family of PEXTR/PINSR instructions they
     692             :         // also introduced PEXTRW with a new opcode 0x15 that can extract directly to
     693             :         // memory. This instruction is, of course, not compatible with MMX/SSE2 one.
     694           0 :         if (instId == X86Inst::kIdPextrw && count > 0 && !operands[0].isMem()) {
     695             :           out.remove(CpuInfo::kX86FeatureSSE4_1);
     696             :         }
     697             :       }
     698             :     }
     699             : 
     700             :     // Check for AVX vs AVX2 overlap.
     701           0 :     if (out.has(CpuInfo::kX86FeatureAVX) && out.has(CpuInfo::kX86FeatureAVX2)) {
     702             :       bool isAVX2 = true;
     703             :       // Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but
     704             :       // only version that uses memory as a source operand. AVX2 then added support
     705             :       // for register source operand.
     706           0 :       if (instId == X86Inst::kIdVbroadcastss || instId == X86Inst::kIdVbroadcastsd) {
     707           0 :         if (count > 1 && operands[0].isMem())
     708             :           isAVX2 = false;
     709             :       }
     710             :       else {
     711             :         // AVX instruction set doesn't support integer operations on YMM registers
     712             :         // as these were later introcuced by AVX2. In our case we have to check if
     713             :         // YMM register(s) are in use and if that is the case this is an AVX2 instruction.
     714           0 :         if (!(mask & Utils::mask(X86Reg::kRegYmm, X86Reg::kRegZmm)))
     715             :           isAVX2 = false;
     716             :       }
     717             : 
     718             :       if (isAVX2)
     719             :         out.remove(CpuInfo::kX86FeatureAVX);
     720             :       else
     721             :         out.remove(CpuInfo::kX86FeatureAVX2);
     722             :     }
     723             : 
     724             :     // Check for AVX|AVX2|FMA|F16C vs AVX512 overlap.
     725           0 :     if (out.has(CpuInfo::kX86FeatureAVX) || out.has(CpuInfo::kX86FeatureAVX2) || out.has(CpuInfo::kX86FeatureFMA) || out.has(CpuInfo::kX86FeatureF16C)) {
     726             :       // Only AVX512-F|BW|DQ allow to encode AVX/AVX2 instructions
     727           0 :       if (out.has(CpuInfo::kX86FeatureAVX512_F) || out.has(CpuInfo::kX86FeatureAVX512_BW) || out.has(CpuInfo::kX86FeatureAVX512_DQ)) {
     728           0 :         uint32_t options = detail.options;
     729             :         uint32_t kAvx512Options = X86Inst::kOptionEvex | X86Inst::_kOptionAvx512Mask;
     730             : 
     731           0 :         if (!(mask & Utils::mask(X86Reg::kRegZmm, X86Reg::kRegK)) && !(options & (kAvx512Options)) && detail.extraReg.getType() != X86Reg::kRegK) {
     732             :           out.remove(CpuInfo::kX86FeatureAVX512_F)
     733             :              .remove(CpuInfo::kX86FeatureAVX512_BW)
     734             :              .remove(CpuInfo::kX86FeatureAVX512_DQ)
     735             :              .remove(CpuInfo::kX86FeatureAVX512_VL);
     736             :         }
     737             :       }
     738             :     }
     739             : 
     740             :     // Remove or keep AVX512_VL feature.
     741           0 :     if (out.has(CpuInfo::kX86FeatureAVX512_VL)) {
     742           0 :       if (!(mask & Utils::mask(X86Reg::kRegZmm)))
     743             :         out.remove(CpuInfo::kX86FeatureAVX512_VL);
     744             :     }
     745             :   }
     746             : 
     747             :   return kErrorOk;
     748             : }
     749             : #endif
     750             : 
     751             : } // asmjit namespace
     752             : } // namespace PLMD
     753             : 
     754             : // [Api-End]
     755             : #include "./asmjit_apiend.h"
     756             : #pragma GCC diagnostic pop
     757             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.15