LCOV - code coverage report
Current view: top level - asmjit - x86emithelper.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 59 202 29.2 %
Date: 2026-11-05 10:19:06 Functions: 6 11 54.5 %

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #include "api-build_p.h"
       8             : #if !defined(ASMJIT_NO_X86)
       9             : 
      10             : #include "formatter.h"
      11             : #include "funcargscontext_p.h"
      12             : #include "moved_string.h"
      13             : #include "support.h"
      14             : #include "type.h"
      15             : #include "radefs_p.h"
      16             : #include "x86emithelper_p.h"
      17             : #include "x86emitter.h"
      18             : #include "x86formatter_p.h"
      19             : #include "x86instapi_p.h"
      20             : 
      21             : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
      22             : 
      23             : // x86::EmitHelper - Utilities
      24             : // ===========================
      25             : 
      26             : static inline uint32_t getXmmMovInst(const FuncFrame& frame) {
      27             :   bool avx = frame.isAvxEnabled();
      28             :   bool aligned = frame.hasAlignedVecSR();
      29             : 
      30           0 :   return aligned ? (avx ? Inst::kIdVmovaps : Inst::kIdMovaps)
      31             :                  : (avx ? Inst::kIdVmovups : Inst::kIdMovups);
      32             : }
      33             : 
      34             : //! Converts `size` to a 'kmov?' instruction.
      35           0 : static inline uint32_t kmovInstFromSize(uint32_t size) noexcept {
      36           0 :   switch (size) {
      37             :     case  1: return Inst::kIdKmovb;
      38           0 :     case  2: return Inst::kIdKmovw;
      39           0 :     case  4: return Inst::kIdKmovd;
      40           0 :     case  8: return Inst::kIdKmovq;
      41           0 :     default: return Inst::kIdNone;
      42             :   }
      43             : }
      44             : 
      45             : static inline uint32_t makeCastOp(TypeId dst, TypeId src) noexcept {
      46           0 :   return (uint32_t(dst) << 8) | uint32_t(src);
      47             : }
      48             : 
      49             : // x86::EmitHelper - Emit Reg Move
      50             : // ===============================
      51             : 
      52       50221 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove(
      53             :   const Operand_& dst_,
      54             :   const Operand_& src_, TypeId typeId, const char* comment) {
      55             : 
      56             :   // Invalid or abstract TypeIds are not allowed.
      57             :   ASMJIT_ASSERT(TypeUtils::isValid(typeId) && !TypeUtils::isAbstract(typeId));
      58             : 
      59             :   Operand dst(dst_);
      60             :   Operand src(src_);
      61             : 
      62             :   InstId instId = Inst::kIdNone;
      63             :   uint32_t memFlags = 0;
      64             :   uint32_t overrideMemSize = 0;
      65             : 
      66             :   enum MemFlags : uint32_t {
      67             :     kDstMem = 0x1,
      68             :     kSrcMem = 0x2
      69             :   };
      70             : 
      71             :   // Detect memory operands and patch them to have the same size as the register. BaseCompiler always sets memory size
      72             :   // of allocs and spills, so it shouldn't be really necessary, however, after this function was separated from Compiler
      73             :   // it's better to make sure that the size is always specified, as we can use 'movzx' and 'movsx' that rely on it.
      74       50221 :   if (dst.isMem()) { memFlags |= kDstMem; dst.as<Mem>().setSize(src.size()); }
      75       50221 :   if (src.isMem()) { memFlags |= kSrcMem; src.as<Mem>().setSize(dst.size()); }
      76             : 
      77       50221 :   switch (typeId) {
      78           0 :     case TypeId::kInt8:
      79             :     case TypeId::kUInt8:
      80             :     case TypeId::kInt16:
      81             :     case TypeId::kUInt16:
      82             :       // Special case - 'movzx' load.
      83           0 :       if (memFlags & kSrcMem) {
      84             :         instId = Inst::kIdMovzx;
      85             :         dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
      86             :         break;
      87             :       }
      88             : 
      89           0 :       if (!memFlags) {
      90             :         // Change both destination and source registers to GPD (safer, no dependencies).
      91             :         dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
      92             :         src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
      93             :       }
      94             :       ASMJIT_FALLTHROUGH;
      95             : 
      96             :     case TypeId::kInt32:
      97             :     case TypeId::kUInt32:
      98             :     case TypeId::kInt64:
      99             :     case TypeId::kUInt64:
     100             :       instId = Inst::kIdMov;
     101             :       break;
     102             : 
     103           0 :     case TypeId::kMmx32:
     104             :       instId = Inst::kIdMovd;
     105           0 :       if (memFlags) break;
     106             :       ASMJIT_FALLTHROUGH;
     107             : 
     108             :     case TypeId::kMmx64 : instId = Inst::kIdMovq ; break;
     109             :     case TypeId::kMask8 : instId = Inst::kIdKmovb; break;
     110             :     case TypeId::kMask16: instId = Inst::kIdKmovw; break;
     111             :     case TypeId::kMask32: instId = Inst::kIdKmovd; break;
     112             :     case TypeId::kMask64: instId = Inst::kIdKmovq; break;
     113             : 
     114             :     default: {
     115             :       TypeId scalarTypeId = TypeUtils::scalarOf(typeId);
     116       50201 :       if (TypeUtils::isVec32(typeId) && memFlags) {
     117             :         overrideMemSize = 4;
     118           0 :         if (scalarTypeId == TypeId::kFloat32)
     119           0 :           instId = _avxEnabled ? Inst::kIdVmovss : Inst::kIdMovss;
     120             :         else
     121           0 :           instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
     122             :         break;
     123             :       }
     124             : 
     125       50201 :       if (TypeUtils::isVec64(typeId) && memFlags) {
     126             :         overrideMemSize = 8;
     127       48416 :         if (scalarTypeId == TypeId::kFloat64)
     128       48416 :           instId = _avxEnabled ? Inst::kIdVmovsd : Inst::kIdMovsd;
     129             :         else
     130           0 :           instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
     131             :         break;
     132             :       }
     133             : 
     134        1785 :       if (scalarTypeId == TypeId::kFloat32)
     135           0 :         instId = _avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps;
     136        1785 :       else if (scalarTypeId == TypeId::kFloat64)
     137        1785 :         instId = _avxEnabled ? Inst::kIdVmovapd : Inst::kIdMovapd;
     138           0 :       else if (!_avx512Enabled)
     139           0 :         instId = _avxEnabled ? Inst::kIdVmovdqa : Inst::kIdMovdqa;
     140             :       else
     141             :         instId = Inst::kIdVmovdqa32;
     142             :       break;
     143             :     }
     144             :   }
     145             : 
     146             :   if (!instId)
     147             :     return DebugUtils::errored(kErrorInvalidState);
     148             : 
     149       50221 :   if (overrideMemSize) {
     150       48416 :     if (dst.isMem()) dst.as<Mem>().setSize(overrideMemSize);
     151       48416 :     if (src.isMem()) src.as<Mem>().setSize(overrideMemSize);
     152             :   }
     153             : 
     154       50221 :   _emitter->setInlineComment(comment);
     155       50221 :   return _emitter->emit(instId, dst, src);
     156             : }
     157             : 
     158             : // x86::EmitHelper - Emit Arg Move
     159             : // ===============================
     160             : 
     161           0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitArgMove(
     162             :   const BaseReg& dst_, TypeId dstTypeId,
     163             :   const Operand_& src_, TypeId srcTypeId, const char* comment) {
     164             : 
     165             :   // Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
     166           0 :   if (dstTypeId == TypeId::kVoid) {
     167           0 :     const ArchTraits& archTraits = ArchTraits::byArch(_emitter->arch());
     168             :     dstTypeId = archTraits.regTypeToTypeId(dst_.type());
     169             :   }
     170             : 
     171             :   // Invalid or abstract TypeIds are not allowed.
     172             :   ASMJIT_ASSERT(TypeUtils::isValid(dstTypeId) && !TypeUtils::isAbstract(dstTypeId));
     173             :   ASMJIT_ASSERT(TypeUtils::isValid(srcTypeId) && !TypeUtils::isAbstract(srcTypeId));
     174             : 
     175             :   Reg dst(dst_.as<Reg>());
     176             :   Operand src(src_);
     177             : 
     178             :   uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
     179             :   uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
     180             : 
     181             :   InstId instId = Inst::kIdNone;
     182             : 
     183             :   // Not a real loop, just 'break' is nicer than 'goto'.
     184             :   for (;;) {
     185           0 :     if (TypeUtils::isInt(dstTypeId)) {
     186           0 :       if (TypeUtils::isInt(srcTypeId)) {
     187             :         instId = Inst::kIdMovsx;
     188             :         uint32_t castOp = makeCastOp(dstTypeId, srcTypeId);
     189             : 
     190             :         // Sign extend by using 'movsx'.
     191             :         if (castOp == makeCastOp(TypeId::kInt16, TypeId::kInt8 ) ||
     192             :             castOp == makeCastOp(TypeId::kInt32, TypeId::kInt8 ) ||
     193             :             castOp == makeCastOp(TypeId::kInt32, TypeId::kInt16) ||
     194             :             castOp == makeCastOp(TypeId::kInt64, TypeId::kInt8 ) ||
     195             :             castOp == makeCastOp(TypeId::kInt64, TypeId::kInt16))
     196             :           break;
     197             : 
     198             :         // Sign extend by using 'movsxd'.
     199             :         instId = Inst::kIdMovsxd;
     200             :         if (castOp == makeCastOp(TypeId::kInt64, TypeId::kInt32))
     201             :           break;
     202             :       }
     203             : 
     204           0 :       if (TypeUtils::isInt(srcTypeId) || src_.isMem()) {
     205             :         // Zero extend by using 'movzx' or 'mov'.
     206           0 :         if (dstSize <= 4 && srcSize < 4) {
     207             :           instId = Inst::kIdMovzx;
     208           0 :           dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     209             :         }
     210             :         else {
     211             :           // We should have caught all possibilities where `srcSize` is less than 4, so we don't have to worry
     212             :           // about 'movzx' anymore. Minimum size is enough to determine if we want 32-bit or 64-bit move.
     213             :           instId = Inst::kIdMov;
     214             :           srcSize = Support::min(srcSize, dstSize);
     215             : 
     216           0 :           dst.setSignature(srcSize == 4 ? Reg::signatureOfT<RegType::kX86_Gpd>()
     217             :                                         : Reg::signatureOfT<RegType::kX86_Gpq>());
     218           0 :           if (src.isReg())
     219             :             src.setSignature(dst.signature());
     220             :         }
     221             :         break;
     222             :       }
     223             : 
     224             :       // NOTE: The previous branch caught all memory sources, from here it's always register to register conversion,
     225             :       // so catch the remaining cases.
     226             :       srcSize = Support::min(srcSize, dstSize);
     227             : 
     228           0 :       if (TypeUtils::isMmx(srcTypeId)) {
     229             :         // 64-bit move.
     230             :         instId = Inst::kIdMovq;
     231           0 :         if (srcSize == 8)
     232             :           break;
     233             : 
     234             :         // 32-bit move.
     235             :         instId = Inst::kIdMovd;
     236             :         dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     237           0 :         break;
     238             :       }
     239             : 
     240           0 :       if (TypeUtils::isMask(srcTypeId)) {
     241           0 :         instId = kmovInstFromSize(srcSize);
     242           0 :         dst.setSignature(srcSize <= 4 ? Reg::signatureOfT<RegType::kX86_Gpd>()
     243             :                                       : Reg::signatureOfT<RegType::kX86_Gpq>());
     244           0 :         break;
     245             :       }
     246             : 
     247           0 :       if (TypeUtils::isVec(srcTypeId)) {
     248             :         // 64-bit move.
     249           0 :         instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
     250           0 :         if (srcSize == 8)
     251             :           break;
     252             : 
     253             :         // 32-bit move.
     254           0 :         instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
     255             :         dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     256           0 :         break;
     257             :       }
     258             :     }
     259             : 
     260           0 :     if (TypeUtils::isMmx(dstTypeId)) {
     261             :       instId = Inst::kIdMovq;
     262             :       srcSize = Support::min(srcSize, dstSize);
     263             : 
     264           0 :       if (TypeUtils::isInt(srcTypeId) || src.isMem()) {
     265             :         // 64-bit move.
     266           0 :         if (srcSize == 8)
     267             :           break;
     268             : 
     269             :         // 32-bit move.
     270             :         instId = Inst::kIdMovd;
     271           0 :         if (src.isReg())
     272             :           src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     273             :         break;
     274             :       }
     275             : 
     276           0 :       if (TypeUtils::isMmx(srcTypeId))
     277             :         break;
     278             : 
     279             :       // This will hurt if AVX is enabled.
     280             :       instId = Inst::kIdMovdq2q;
     281           0 :       if (TypeUtils::isVec(srcTypeId))
     282             :         break;
     283             :     }
     284             : 
     285           0 :     if (TypeUtils::isMask(dstTypeId)) {
     286             :       srcSize = Support::min(srcSize, dstSize);
     287             : 
     288           0 :       if (TypeUtils::isInt(srcTypeId) || TypeUtils::isMask(srcTypeId) || src.isMem()) {
     289           0 :         instId = kmovInstFromSize(srcSize);
     290           0 :         if (Reg::isGp(src) && srcSize <= 4)
     291             :           src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     292             :         break;
     293             :       }
     294             :     }
     295             : 
     296           0 :     if (TypeUtils::isVec(dstTypeId)) {
     297             :       // By default set destination to XMM, will be set to YMM|ZMM if needed.
     298             :       dst.setSignature(Reg::signatureOfT<RegType::kX86_Xmm>());
     299             : 
     300             :       // This will hurt if AVX is enabled.
     301           0 :       if (Reg::isMm(src)) {
     302             :         // 64-bit move.
     303             :         instId = Inst::kIdMovq2dq;
     304             :         break;
     305             :       }
     306             : 
     307             :       // Argument conversion.
     308             :       TypeId dstScalarId = TypeUtils::scalarOf(dstTypeId);
     309             :       TypeId srcScalarId = TypeUtils::scalarOf(srcTypeId);
     310             : 
     311           0 :       if (dstScalarId == TypeId::kFloat32 && srcScalarId == TypeId::kFloat64) {
     312           0 :         srcSize = Support::min(dstSize * 2, srcSize);
     313           0 :         dstSize = srcSize / 2;
     314             : 
     315           0 :         if (srcSize <= 8)
     316           0 :           instId = _avxEnabled ? Inst::kIdVcvtss2sd : Inst::kIdCvtss2sd;
     317             :         else
     318           0 :           instId = _avxEnabled ? Inst::kIdVcvtps2pd : Inst::kIdCvtps2pd;
     319             : 
     320           0 :         if (dstSize == 32)
     321             :           dst.setSignature(Reg::signatureOfT<RegType::kX86_Ymm>());
     322           0 :         if (src.isReg())
     323           0 :           src.setSignature(Reg::signatureOfVecBySize(srcSize));
     324             :         break;
     325             :       }
     326             : 
     327           0 :       if (dstScalarId == TypeId::kFloat64 && srcScalarId == TypeId::kFloat32) {
     328           0 :         srcSize = Support::min(dstSize, srcSize * 2) / 2;
     329           0 :         dstSize = srcSize * 2;
     330             : 
     331           0 :         if (srcSize <= 4)
     332           0 :           instId = _avxEnabled ? Inst::kIdVcvtsd2ss : Inst::kIdCvtsd2ss;
     333             :         else
     334           0 :           instId = _avxEnabled ? Inst::kIdVcvtpd2ps : Inst::kIdCvtpd2ps;
     335             : 
     336           0 :         dst.setSignature(Reg::signatureOfVecBySize(dstSize));
     337           0 :         if (src.isReg() && srcSize >= 32)
     338             :           src.setSignature(Reg::signatureOfT<RegType::kX86_Ymm>());
     339             :         break;
     340             :       }
     341             : 
     342             :       srcSize = Support::min(srcSize, dstSize);
     343           0 :       if (Reg::isGp(src) || src.isMem()) {
     344             :         // 32-bit move.
     345           0 :         if (srcSize <= 4) {
     346           0 :           instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
     347             :           if (src.isReg())
     348             :             src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
     349             :           break;
     350             :         }
     351             : 
     352             :         // 64-bit move.
     353           0 :         if (srcSize == 8) {
     354           0 :           instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
     355             :           break;
     356             :         }
     357             :       }
     358             : 
     359           0 :       if (Reg::isVec(src) || src.isMem()) {
     360           0 :         instId = _avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps;
     361             : 
     362           0 :         if (src.isMem() && srcSize < _emitter->environment().stackAlignment())
     363           0 :           instId = _avxEnabled ? Inst::kIdVmovups : Inst::kIdMovups;
     364             : 
     365           0 :         OperandSignature signature = Reg::signatureOfVecBySize(srcSize);
     366             :         dst.setSignature(signature);
     367           0 :         if (src.isReg())
     368             :           src.setSignature(signature);
     369             :         break;
     370             :       }
     371             :     }
     372             : 
     373             :     return DebugUtils::errored(kErrorInvalidState);
     374             :   }
     375             : 
     376           0 :   if (src.isMem())
     377           0 :     src.as<Mem>().setSize(srcSize);
     378             : 
     379           0 :   _emitter->setInlineComment(comment);
     380           0 :   return _emitter->emit(instId, dst, src);
     381             : }
     382             : 
     383           0 : Error EmitHelper::emitRegSwap(
     384             :   const BaseReg& a,
     385             :   const BaseReg& b, const char* comment) {
     386             : 
     387           0 :   if (a.isGp() && b.isGp()) {
     388           0 :     _emitter->setInlineComment(comment);
     389           0 :     return _emitter->emit(Inst::kIdXchg, a, b);
     390             :   }
     391             :   else
     392             :     return DebugUtils::errored(kErrorInvalidState);
     393             : }
     394             : 
     395             : // x86::EmitHelper - Emit Prolog & Epilog
     396             : // ======================================
     397             : 
     398           0 : static inline void X86Internal_setupSaveRestoreInfo(RegGroup group, const FuncFrame& frame, Reg& xReg, uint32_t& xInst, uint32_t& xSize) noexcept {
     399           0 :   switch (group) {
     400           0 :     case RegGroup::kVec:
     401           0 :       xReg = xmm(0);
     402           0 :       xInst = getXmmMovInst(frame);
     403           0 :       xSize = xReg.size();
     404           0 :       break;
     405           0 :     case RegGroup::kX86_K:
     406           0 :       xReg = k(0);
     407           0 :       xInst = Inst::kIdKmovq;
     408           0 :       xSize = xReg.size();
     409           0 :       break;
     410           0 :     case RegGroup::kX86_MM:
     411           0 :       xReg = mm(0);
     412           0 :       xInst = Inst::kIdMovq;
     413           0 :       xSize = xReg.size();
     414           0 :       break;
     415             :     default:
     416             :       break;
     417             :   }
     418           0 : }
     419             : 
     420       27492 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
     421       27492 :   Emitter* emitter = _emitter->as<Emitter>();
     422             :   uint32_t gpSaved = frame.savedRegs(RegGroup::kGp);
     423             : 
     424             :   Gp zsp = emitter->zsp();   // ESP|RSP register.
     425             :   Gp zbp = emitter->zbp();   // EBP|RBP register.
     426             :   Gp gpReg = zsp;            // General purpose register (temporary).
     427             :   Gp saReg = zsp;            // Stack-arguments base pointer.
     428             : 
     429             :   // Emit: 'push zbp'
     430             :   //       'mov  zbp, zsp'.
     431       27492 :   if (frame.hasPreservedFP()) {
     432           0 :     gpSaved &= ~Support::bitMask(Gp::kIdBp);
     433           0 :     ASMJIT_PROPAGATE(emitter->push(zbp));
     434           0 :     ASMJIT_PROPAGATE(emitter->mov(zbp, zsp));
     435             :   }
     436             : 
     437             :   // Emit: 'push gp' sequence.
     438             :   {
     439             :     Support::BitWordIterator<RegMask> it(gpSaved);
     440       27492 :     while (it.hasNext()) {
     441             :       gpReg.setId(it.next());
     442           0 :       ASMJIT_PROPAGATE(emitter->push(gpReg));
     443             :     }
     444             :   }
     445             : 
     446             :   // Emit: 'mov saReg, zsp'.
     447             :   uint32_t saRegId = frame.saRegId();
     448       27492 :   if (saRegId != BaseReg::kIdBad && saRegId != Gp::kIdSp) {
     449             :     saReg.setId(saRegId);
     450           0 :     if (frame.hasPreservedFP()) {
     451           0 :       if (saRegId != Gp::kIdBp)
     452           0 :         ASMJIT_PROPAGATE(emitter->mov(saReg, zbp));
     453             :     }
     454             :     else {
     455           0 :       ASMJIT_PROPAGATE(emitter->mov(saReg, zsp));
     456             :     }
     457             :   }
     458             : 
     459             :   // Emit: 'and zsp, StackAlignment'.
     460       27492 :   if (frame.hasDynamicAlignment()) {
     461           0 :     ASMJIT_PROPAGATE(emitter->and_(zsp, -int32_t(frame.finalStackAlignment())));
     462             :   }
     463             : 
     464             :   // Emit: 'sub zsp, StackAdjustment'.
     465       27492 :   if (frame.hasStackAdjustment()) {
     466        4990 :     ASMJIT_PROPAGATE(emitter->sub(zsp, frame.stackAdjustment()));
     467             :   }
     468             : 
     469             :   // Emit: 'mov [zsp + DAOffset], saReg'.
     470       27492 :   if (frame.hasDynamicAlignment() && frame.hasDAOffset()) {
     471           0 :     Mem saMem = ptr(zsp, int32_t(frame.daOffset()));
     472           0 :     ASMJIT_PROPAGATE(emitter->mov(saMem, saReg));
     473             :   }
     474             : 
     475             :   // Emit 'movxxx [zsp + X], {[x|y|z]mm, k}'.
     476             :   {
     477       27492 :     Reg xReg;
     478       27492 :     Mem xBase = ptr(zsp, int32_t(frame.extraRegSaveOffset()));
     479             : 
     480             :     uint32_t xInst;
     481             :     uint32_t xSize;
     482             : 
     483      109968 :     for (RegGroup group : Support::EnumValues<RegGroup, RegGroup(1), RegGroup::kMaxVirt>{}) {
     484             :       Support::BitWordIterator<RegMask> it(frame.savedRegs(group));
     485       82476 :       if (it.hasNext()) {
     486           0 :         X86Internal_setupSaveRestoreInfo(group, frame, xReg, xInst, xSize);
     487             :         do {
     488             :           xReg.setId(it.next());
     489           0 :           ASMJIT_PROPAGATE(emitter->emit(xInst, xBase, xReg));
     490           0 :           xBase.addOffsetLo32(int32_t(xSize));
     491           0 :         } while (it.hasNext());
     492             :       }
     493             :     }
     494             :   }
     495             : 
     496       27492 :   return kErrorOk;
     497             : }
     498             : 
     499       27492 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
     500       27492 :   Emitter* emitter = _emitter->as<Emitter>();
     501             : 
     502             :   uint32_t i;
     503             :   uint32_t regId;
     504             : 
     505       27492 :   uint32_t registerSize = emitter->registerSize();
     506             :   uint32_t gpSaved = frame.savedRegs(RegGroup::kGp);
     507             : 
     508             :   Gp zsp = emitter->zsp();   // ESP|RSP register.
     509             :   Gp zbp = emitter->zbp();   // EBP|RBP register.
     510             :   Gp gpReg = emitter->zsp(); // General purpose register (temporary).
     511             : 
     512             :   // Don't emit 'pop zbp' in the pop sequence, this case is handled separately.
     513       27492 :   if (frame.hasPreservedFP())
     514           0 :     gpSaved &= ~Support::bitMask(Gp::kIdBp);
     515             : 
     516             :   // Emit 'movxxx {[x|y|z]mm, k}, [zsp + X]'.
     517             :   {
     518       27492 :     Reg xReg;
     519       27492 :     Mem xBase = ptr(zsp, int32_t(frame.extraRegSaveOffset()));
     520             : 
     521             :     uint32_t xInst;
     522             :     uint32_t xSize;
     523             : 
     524      109968 :     for (RegGroup group : Support::EnumValues<RegGroup, RegGroup(1), RegGroup::kMaxVirt>{}) {
     525             :       Support::BitWordIterator<RegMask> it(frame.savedRegs(group));
     526       82476 :       if (it.hasNext()) {
     527           0 :         X86Internal_setupSaveRestoreInfo(group, frame, xReg, xInst, xSize);
     528             :         do {
     529             :           xReg.setId(it.next());
     530           0 :           ASMJIT_PROPAGATE(emitter->emit(xInst, xReg, xBase));
     531           0 :           xBase.addOffsetLo32(int32_t(xSize));
     532           0 :         } while (it.hasNext());
     533             :       }
     534             :     }
     535             :   }
     536             : 
     537             :   // Emit 'emms' and/or 'vzeroupper'.
     538       27492 :   if (frame.hasMmxCleanup()) ASMJIT_PROPAGATE(emitter->emms());
     539       27492 :   if (frame.hasAvxCleanup()) ASMJIT_PROPAGATE(emitter->vzeroupper());
     540             : 
     541       27492 :   if (frame.hasPreservedFP()) {
     542             :     // Emit 'mov zsp, zbp' or 'lea zsp, [zbp - x]'
     543           0 :     int32_t count = int32_t(frame.pushPopSaveSize() - registerSize);
     544           0 :     if (!count)
     545           0 :       ASMJIT_PROPAGATE(emitter->mov(zsp, zbp));
     546             :     else
     547           0 :       ASMJIT_PROPAGATE(emitter->lea(zsp, ptr(zbp, -count)));
     548             :   }
     549             :   else {
     550       27492 :     if (frame.hasDynamicAlignment() && frame.hasDAOffset()) {
     551             :       // Emit 'mov zsp, [zsp + DsaSlot]'.
     552           0 :       Mem saMem = ptr(zsp, int32_t(frame.daOffset()));
     553           0 :       ASMJIT_PROPAGATE(emitter->mov(zsp, saMem));
     554             :     }
     555       27492 :     else if (frame.hasStackAdjustment()) {
     556             :       // Emit 'add zsp, StackAdjustment'.
     557        4990 :       ASMJIT_PROPAGATE(emitter->add(zsp, int32_t(frame.stackAdjustment())));
     558             :     }
     559             :   }
     560             : 
     561             :   // Emit 'pop gp' sequence.
     562       27492 :   if (gpSaved) {
     563             :     i = gpSaved;
     564             :     regId = 16;
     565             : 
     566             :     do {
     567           0 :       regId--;
     568           0 :       if (i & 0x8000) {
     569             :         gpReg.setId(regId);
     570           0 :         ASMJIT_PROPAGATE(emitter->pop(gpReg));
     571             :       }
     572           0 :       i <<= 1;
     573           0 :     } while (regId != 0);
     574             :   }
     575             : 
     576             :   // Emit 'pop zbp'.
     577       27492 :   if (frame.hasPreservedFP())
     578           0 :     ASMJIT_PROPAGATE(emitter->pop(zbp));
     579             : 
     580             :   // Emit 'ret' or 'ret x'.
     581       27492 :   if (frame.hasCalleeStackCleanup())
     582           0 :     ASMJIT_PROPAGATE(emitter->emit(Inst::kIdRet, int(frame.calleeStackCleanup())));
     583             :   else
     584       27492 :     ASMJIT_PROPAGATE(emitter->emit(Inst::kIdRet));
     585             : 
     586             :   return kErrorOk;
     587             : }
     588             : 
     589       27492 : static Error ASMJIT_CDECL Emitter_emitProlog(BaseEmitter* emitter, const FuncFrame& frame) {
     590             :   EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
     591       27492 :   return emitHelper.emitProlog(frame);
     592             : }
     593             : 
     594       27492 : static Error ASMJIT_CDECL Emitter_emitEpilog(BaseEmitter* emitter, const FuncFrame& frame) {
     595             :   EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
     596       27492 :   return emitHelper.emitEpilog(frame);
     597             : }
     598             : 
     599           0 : static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) {
     600             :   EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
     601           0 :   return emitHelper.emitArgsAssignment(frame, args);
     602             : }
     603             : 
     604       54984 : void assignEmitterFuncs(BaseEmitter* emitter) {
     605       54984 :   emitter->_funcs.emitProlog = Emitter_emitProlog;
     606       54984 :   emitter->_funcs.emitEpilog = Emitter_emitEpilog;
     607       54984 :   emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
     608             : 
     609             : #ifndef ASMJIT_NO_LOGGING
     610       54984 :   emitter->_funcs.formatInstruction = FormatterInternal::formatInstruction;
     611             : #endif
     612             : 
     613             : #ifndef ASMJIT_NO_VALIDATION
     614       54984 :   emitter->_funcs.validate = InstInternal::validate;
     615             : #endif
     616       54984 : }
     617             : 
     618             : ASMJIT_END_SUB_NAMESPACE
     619             : 
     620             : #endif // !ASMJIT_NO_X86
     621             : 
     622             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16