LCOV - code coverage report
Current view: top level - asmjit - x86regalloc.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 466 1055 44.2 %
Date: 2024-10-11 08:09:49 Functions: 17 29 58.6 %

          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             : // [Guard]
      33             : #include "./asmjit_build.h"
      34             : #if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_DISABLE_COMPILER)
      35             : 
      36             : // [Dependencies]
      37             : #include "./cpuinfo.h"
      38             : #include "./utils.h"
      39             : #include "./x86assembler.h"
      40             : #include "./x86compiler.h"
      41             : #include "./x86internal_p.h"
      42             : #include "./x86regalloc_p.h"
      43             : 
      44             : // [Api-Begin]
      45             : #include "./asmjit_apibegin.h"
      46             : 
      47             : namespace PLMD {
      48             : namespace asmjit {
      49             : 
      50             : // ============================================================================
      51             : // [Forward Declarations]
      52             : // ============================================================================
      53             : 
      54             : enum { kCompilerDefaultLookAhead = 64 };
      55             : 
      56             : static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount);
      57             : 
      58             : // ============================================================================
      59             : // [asmjit::X86RAPass - SpecialInst]
      60             : // ============================================================================
      61             : 
      62             : struct X86SpecialInst {
      63             :   uint8_t inReg;
      64             :   uint8_t outReg;
      65             :   uint16_t flags;
      66             : };
      67             : 
      68             : static ASMJIT_INLINE const X86SpecialInst* X86SpecialInst_get(uint32_t instId, const Operand* opArray, uint32_t opCount) noexcept {
      69             :   enum { kAny = Globals::kInvalidRegId };
      70             : 
      71             : #define R(ri) { uint8_t(ri)  , uint8_t(kAny), uint16_t(TiedReg::kRReg) }
      72             : #define W(ri) { uint8_t(kAny), uint8_t(ri)  , uint16_t(TiedReg::kWReg) }
      73             : #define X(ri) { uint8_t(ri)  , uint8_t(ri)  , uint16_t(TiedReg::kXReg) }
      74             : #define NONE() { uint8_t(kAny), uint8_t(kAny), 0 }
      75             :   static const X86SpecialInst instCpuid[]        = { X(X86Gp::kIdAx), W(X86Gp::kIdBx), X(X86Gp::kIdCx), W(X86Gp::kIdDx) };
      76             :   static const X86SpecialInst instCbwCdqeCwde[]  = { X(X86Gp::kIdAx) };
      77             :   static const X86SpecialInst instCdqCwdCqo[]    = { W(X86Gp::kIdDx), R(X86Gp::kIdAx) };
      78             :   static const X86SpecialInst instCmpxchg[]      = { X(kAny), R(kAny), X(X86Gp::kIdAx) };
      79             :   static const X86SpecialInst instCmpxchg8b16b[] = { NONE(), X(X86Gp::kIdDx), X(X86Gp::kIdAx), R(X86Gp::kIdCx), R(X86Gp::kIdBx) };
      80             :   static const X86SpecialInst instDaaDas[]       = { X(X86Gp::kIdAx) };
      81             :   static const X86SpecialInst instDiv2[]         = { X(X86Gp::kIdAx), R(kAny) };
      82             :   static const X86SpecialInst instDiv3[]         = { X(X86Gp::kIdDx), X(X86Gp::kIdAx), R(kAny) };
      83             :   static const X86SpecialInst instJecxz[]        = { R(X86Gp::kIdCx) };
      84             :   static const X86SpecialInst instMul2[]         = { X(X86Gp::kIdAx), R(kAny) };
      85             :   static const X86SpecialInst instMul3[]         = { W(X86Gp::kIdDx), X(X86Gp::kIdAx), R(kAny) };
      86             :   static const X86SpecialInst instMulx[]         = { W(kAny), W(kAny), R(kAny), R(X86Gp::kIdDx) };
      87             :   static const X86SpecialInst instLahf[]         = { W(X86Gp::kIdAx) };
      88             :   static const X86SpecialInst instSahf[]         = { R(X86Gp::kIdAx) };
      89             :   static const X86SpecialInst instMaskmovq[]     = { R(kAny), R(kAny), R(X86Gp::kIdDi) };
      90             :   static const X86SpecialInst instRdtscRdtscp[]  = { W(X86Gp::kIdDx), W(X86Gp::kIdAx), W(X86Gp::kIdCx) };
      91             :   static const X86SpecialInst instRot[]          = { X(kAny), R(X86Gp::kIdCx) };
      92             :   static const X86SpecialInst instShldShrd[]     = { X(kAny), R(kAny), R(X86Gp::kIdCx) };
      93             :   static const X86SpecialInst instThirdXMM0[]    = { W(kAny), R(kAny), R(0) };
      94             :   static const X86SpecialInst instPcmpestri[]    = { R(kAny), R(kAny), NONE(), W(X86Gp::kIdCx) };
      95             :   static const X86SpecialInst instPcmpestrm[]    = { R(kAny), R(kAny), NONE(), W(0) };
      96             :   static const X86SpecialInst instPcmpistri[]    = { R(kAny), R(kAny), NONE(), W(X86Gp::kIdCx), R(X86Gp::kIdAx), R(X86Gp::kIdDx) };
      97             :   static const X86SpecialInst instPcmpistrm[]    = { R(kAny), R(kAny), NONE(), W(0)           , R(X86Gp::kIdAx), R(X86Gp::kIdDx) };
      98             :   static const X86SpecialInst instXsaveXrstor[]  = { W(kAny), R(X86Gp::kIdDx), R(X86Gp::kIdAx) };
      99             :   static const X86SpecialInst instReadMR[]       = { W(X86Gp::kIdDx), W(X86Gp::kIdAx), R(X86Gp::kIdCx) };
     100             :   static const X86SpecialInst instWriteMR[]      = { R(X86Gp::kIdDx), R(X86Gp::kIdAx), R(X86Gp::kIdCx) };
     101             : 
     102             :   static const X86SpecialInst instCmps[]         = { X(X86Gp::kIdSi), X(X86Gp::kIdDi) };
     103             :   static const X86SpecialInst instLods[]         = { W(X86Gp::kIdAx), X(X86Gp::kIdSi) };
     104             :   static const X86SpecialInst instMovs[]         = { X(X86Gp::kIdDi), X(X86Gp::kIdSi) };
     105             :   static const X86SpecialInst instScas[]         = { X(X86Gp::kIdDi), R(X86Gp::kIdAx) };
     106             :   static const X86SpecialInst instStos[]         = { X(X86Gp::kIdDi), R(X86Gp::kIdAx) };
     107             : #undef NONE
     108             : #undef X
     109             : #undef W
     110             : #undef R
     111             : 
     112           0 :   switch (instId) {
     113             :     case X86Inst::kIdCpuid      : return instCpuid;
     114           0 :     case X86Inst::kIdCbw        :
     115             :     case X86Inst::kIdCdqe       :
     116           0 :     case X86Inst::kIdCwde       : return instCbwCdqeCwde;
     117           0 :     case X86Inst::kIdCdq        :
     118             :     case X86Inst::kIdCwd        :
     119           0 :     case X86Inst::kIdCqo        : return instCdqCwdCqo;
     120           0 :     case X86Inst::kIdCmps       : return instCmps;
     121           0 :     case X86Inst::kIdCmpxchg    : return instCmpxchg;
     122           0 :     case X86Inst::kIdCmpxchg8b  :
     123           0 :     case X86Inst::kIdCmpxchg16b : return instCmpxchg8b16b;
     124           0 :     case X86Inst::kIdDaa        :
     125           0 :     case X86Inst::kIdDas        : return instDaaDas;
     126           0 :     case X86Inst::kIdDiv        : return (opCount == 2) ? instDiv2 : instDiv3;
     127           0 :     case X86Inst::kIdIdiv       : return (opCount == 2) ? instDiv2 : instDiv3;
     128           0 :     case X86Inst::kIdImul       : if (opCount == 2) return nullptr;
     129           0 :                                   if (opCount == 3 && !(opArray[0].isReg() && opArray[1].isReg() && opArray[2].isRegOrMem())) return nullptr;
     130             :                                   ASMJIT_FALLTHROUGH;
     131           0 :     case X86Inst::kIdMul        : return (opCount == 2) ? instMul2 : instMul3;
     132           0 :     case X86Inst::kIdMulx       : return instMulx;
     133           0 :     case X86Inst::kIdJecxz      : return instJecxz;
     134           0 :     case X86Inst::kIdLods       : return instLods;
     135           0 :     case X86Inst::kIdMovs       : return instMovs;
     136           0 :     case X86Inst::kIdLahf       : return instLahf;
     137           0 :     case X86Inst::kIdSahf       : return instSahf;
     138           0 :     case X86Inst::kIdMaskmovq   :
     139             :     case X86Inst::kIdMaskmovdqu :
     140           0 :     case X86Inst::kIdVmaskmovdqu: return instMaskmovq;
     141             :     case X86Inst::kIdEnter      : return nullptr; // Not supported.
     142             :     case X86Inst::kIdLeave      : return nullptr; // Not supported.
     143             :     case X86Inst::kIdRet        : return nullptr; // Not supported.
     144             :     case X86Inst::kIdMonitor    : return nullptr; // TODO: [COMPILER] Monitor/MWait.
     145             :     case X86Inst::kIdMwait      : return nullptr; // TODO: [COMPILER] Monitor/MWait.
     146             :     case X86Inst::kIdPop        : return nullptr; // TODO: [COMPILER] Pop/Push.
     147             :     case X86Inst::kIdPush       : return nullptr; // TODO: [COMPILER] Pop/Push.
     148             :     case X86Inst::kIdPopa       : return nullptr; // Not supported.
     149             :     case X86Inst::kIdPopf       : return nullptr; // Not supported.
     150             :     case X86Inst::kIdPusha      : return nullptr; // Not supported.
     151             :     case X86Inst::kIdPushf      : return nullptr; // Not supported.
     152           0 :     case X86Inst::kIdRcl        :
     153             :     case X86Inst::kIdRcr        :
     154             :     case X86Inst::kIdRol        :
     155             :     case X86Inst::kIdRor        :
     156             :     case X86Inst::kIdSal        :
     157             :     case X86Inst::kIdSar        :
     158             :     case X86Inst::kIdShl        : // Rot instruction is special only if the last operand is a variable.
     159           0 :     case X86Inst::kIdShr        : if (!opArray[1].isReg()) return nullptr;
     160             :                                   return instRot;
     161           0 :     case X86Inst::kIdShld       : // Shld/Shrd instruction is special only if the last operand is a variable.
     162           0 :     case X86Inst::kIdShrd       : if (!opArray[2].isReg()) return nullptr;
     163             :                                   return instShldShrd;
     164           0 :     case X86Inst::kIdRdtsc      :
     165           0 :     case X86Inst::kIdRdtscp     : return instRdtscRdtscp;
     166           0 :     case X86Inst::kIdScas       : return instScas;
     167           0 :     case X86Inst::kIdStos       : return instStos;
     168           0 :     case X86Inst::kIdBlendvpd   :
     169             :     case X86Inst::kIdBlendvps   :
     170             :     case X86Inst::kIdPblendvb   :
     171           0 :     case X86Inst::kIdSha256rnds2: return instThirdXMM0;
     172           0 :     case X86Inst::kIdPcmpestri  :
     173           0 :     case X86Inst::kIdVpcmpestri : return instPcmpestri;
     174           0 :     case X86Inst::kIdPcmpistri  :
     175           0 :     case X86Inst::kIdVpcmpistri : return instPcmpistri;
     176           0 :     case X86Inst::kIdPcmpestrm  :
     177           0 :     case X86Inst::kIdVpcmpestrm : return instPcmpestrm;
     178           0 :     case X86Inst::kIdPcmpistrm  :
     179           0 :     case X86Inst::kIdVpcmpistrm : return instPcmpistrm;
     180           0 :     case X86Inst::kIdXrstor     :
     181             :     case X86Inst::kIdXrstor64   :
     182             :     case X86Inst::kIdXsave      :
     183             :     case X86Inst::kIdXsave64    :
     184             :     case X86Inst::kIdXsaveopt   :
     185           0 :     case X86Inst::kIdXsaveopt64 : return instXsaveXrstor;
     186           0 :     case X86Inst::kIdRdmsr      :
     187             :     case X86Inst::kIdRdpmc      :
     188           0 :     case X86Inst::kIdXgetbv     : return instReadMR;
     189           0 :     case X86Inst::kIdWrmsr      :
     190           0 :     case X86Inst::kIdXsetbv     : return instWriteMR;
     191             :     default                     : return nullptr;
     192             :   }
     193             : }
     194             : 
     195             : // ============================================================================
     196             : // [asmjit::X86RAPass - Construction / Destruction]
     197             : // ============================================================================
     198             : 
     199        1944 : X86RAPass::X86RAPass() noexcept : RAPass() {
     200        1944 :   _state = &_x86State;
     201        1944 :   _varMapToVaListOffset = ASMJIT_OFFSET_OF(X86RAData, tiedArray);
     202        1944 : }
     203           0 : X86RAPass::~X86RAPass() noexcept {}
     204             : 
     205             : // ============================================================================
     206             : // [asmjit::X86RAPass - Interface]
     207             : // ============================================================================
     208             : 
     209        1944 : Error X86RAPass::process(Zone* zone) noexcept {
     210        1944 :   return Base::process(zone);
     211             : }
     212             : 
     213        1944 : Error X86RAPass::prepare(CCFunc* func) noexcept {
     214        1944 :   ASMJIT_PROPAGATE(Base::prepare(func));
     215             : 
     216             :   uint32_t archType = cc()->getArchType();
     217        1944 :   _regCount._gp  = archType == ArchInfo::kTypeX86 ? 8 : 16;
     218        1944 :   _regCount._mm  = 8;
     219        1944 :   _regCount._k   = 8;
     220        1944 :   _regCount._vec = archType == ArchInfo::kTypeX86 ? 8 : 16;
     221             :   _zsp = cc()->zsp();
     222             :   _zbp = cc()->zbp();
     223             : 
     224        1944 :   _gaRegs[X86Reg::kKindGp ] = Utils::bits(_regCount.getGp()) & ~Utils::mask(X86Gp::kIdSp);
     225        1944 :   _gaRegs[X86Reg::kKindMm ] = Utils::bits(_regCount.getMm());
     226        1944 :   _gaRegs[X86Reg::kKindK  ] = Utils::bits(_regCount.getK());
     227        1944 :   _gaRegs[X86Reg::kKindVec] = Utils::bits(_regCount.getVec());
     228             : 
     229        1944 :   _x86State.reset(0);
     230             :   _clobberedRegs.reset();
     231             : 
     232        1944 :   _avxEnabled = false;
     233             : 
     234        1944 :   _varBaseRegId = Globals::kInvalidRegId; // Used by patcher.
     235        1944 :   _varBaseOffset = 0;                     // Used by patcher.
     236             : 
     237        1944 :   return kErrorOk;
     238             : }
     239             : 
     240             : // ============================================================================
     241             : // [asmjit::X86RAPass - Emit]
     242             : // ============================================================================
     243             : 
     244         656 : Error X86RAPass::emitMove(VirtReg* vReg, uint32_t dstId, uint32_t srcId, const char* reason) {
     245             :   const char* comment = nullptr;
     246         656 :   if (_emitComments) {
     247           0 :     _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
     248             :     comment = _stringBuilder.getData();
     249             :   }
     250             : 
     251             :   X86Reg dst(X86Reg::fromSignature(vReg->getSignature(), dstId));
     252             :   X86Reg src(X86Reg::fromSignature(vReg->getSignature(), srcId));
     253         656 :   return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
     254             : }
     255             : 
     256        4424 : Error X86RAPass::emitLoad(VirtReg* vReg, uint32_t id, const char* reason) {
     257             :   const char* comment = nullptr;
     258        4424 :   if (_emitComments) {
     259           0 :     _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
     260             :     comment = _stringBuilder.getData();
     261             :   }
     262             : 
     263             :   X86Reg dst(X86Reg::fromSignature(vReg->getSignature(), id));
     264             :   X86Mem src(getVarMem(vReg));
     265        4424 :   return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
     266             : }
     267             : 
     268        4004 : Error X86RAPass::emitSave(VirtReg* vReg, uint32_t id, const char* reason) {
     269             :   const char* comment = nullptr;
     270        4004 :   if (_emitComments) {
     271           0 :     _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
     272             :     comment = _stringBuilder.getData();
     273             :   }
     274             : 
     275             :   X86Mem dst(getVarMem(vReg));
     276             :   X86Reg src(X86Reg::fromSignature(vReg->getSignature(), id));
     277        4004 :   return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
     278             : }
     279             : 
     280           0 : Error X86RAPass::emitSwapGp(VirtReg* dstReg, VirtReg* srcReg, uint32_t dstPhysId, uint32_t srcPhysId, const char* reason) noexcept {
     281             :   ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
     282             :   ASMJIT_ASSERT(srcPhysId != Globals::kInvalidRegId);
     283             : 
     284           0 :   uint32_t is64 = std::max(dstReg->getTypeId(), srcReg->getTypeId()) >= TypeId::kI64;
     285           0 :   uint32_t sign = is64 ? uint32_t(X86RegTraits<X86Reg::kRegGpq>::kSignature)
     286             :                        : uint32_t(X86RegTraits<X86Reg::kRegGpd>::kSignature);
     287             : 
     288             :   X86Reg a = X86Reg::fromSignature(sign, dstPhysId);
     289             :   X86Reg b = X86Reg::fromSignature(sign, srcPhysId);
     290             : 
     291           0 :   ASMJIT_PROPAGATE(cc()->emit(X86Inst::kIdXchg, a, b));
     292           0 :   if (_emitComments)
     293           0 :     cc()->getCursor()->setInlineComment(cc()->_cbDataZone.sformat("[%s] %s, %s", reason, dstReg->getName(), srcReg->getName()));
     294             :   return kErrorOk;
     295             : }
     296             : 
     297         404 : Error X86RAPass::emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept {
     298             :   ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
     299             : 
     300             :   X86Reg r0;
     301             :   Imm imm(*src);
     302             : 
     303         404 :   switch (dstTypeId) {
     304             :     case TypeId::kI8:
     305             :     case TypeId::kU8:
     306             :       imm.truncateTo8Bits();
     307             :       ASMJIT_FALLTHROUGH;
     308             : 
     309           0 :     case TypeId::kI16:
     310             :     case TypeId::kU16:
     311             :       imm.truncateTo16Bits();
     312             :       ASMJIT_FALLTHROUGH;
     313             : 
     314             :     case TypeId::kI32:
     315             :     case TypeId::kU32:
     316           0 : Mov32Truncate:
     317             :       imm.truncateTo32Bits();
     318             :       r0.setX86RegT<X86Reg::kRegGpd>(dstPhysId);
     319           0 :       cc()->emit(X86Inst::kIdMov, r0, imm);
     320           0 :       break;
     321             : 
     322             :     case TypeId::kI64:
     323             :     case TypeId::kU64:
     324             :       // Move to GPD register will also clear the high DWORD of GPQ
     325             :       // register in 64-bit mode.
     326         404 :       if (imm.isUInt32())
     327           0 :         goto Mov32Truncate;
     328             : 
     329             :       r0.setX86RegT<X86Reg::kRegGpq>(dstPhysId);
     330         404 :       cc()->emit(X86Inst::kIdMov, r0, imm);
     331         404 :       break;
     332             : 
     333             :     case TypeId::kF32:
     334             :     case TypeId::kF64:
     335             :       // Compiler doesn't manage FPU stack.
     336             :       ASMJIT_NOT_REACHED();
     337             :       break;
     338             : 
     339             :     case TypeId::kMmx32:
     340             :     case TypeId::kMmx64:
     341             :       // TODO: [COMPILER] EmitMoveImmToReg.
     342             :       break;
     343             : 
     344             :     default:
     345             :       // TODO: [COMPILER] EmitMoveImmToReg.
     346             :       break;
     347             :   }
     348             : 
     349         404 :   return kErrorOk;
     350             : }
     351             : 
     352           0 : Error X86RAPass::emitImmToStack(uint32_t dstTypeId, const X86Mem* dst, const Imm* src) noexcept {
     353             :   X86Mem mem(*dst);
     354             :   Imm imm(*src);
     355             : 
     356             :   // One stack entry has the same size as the native register size. That means
     357             :   // that if we want to move a 32-bit integer on the stack in 64-bit mode, we
     358             :   // need to extend it to a 64-bit integer first. In 32-bit mode, pushing a
     359             :   // 64-bit on stack is done in two steps by pushing low and high parts
     360             :   // separately.
     361             :   uint32_t gpSize = cc()->getGpSize();
     362             : 
     363           0 :   switch (dstTypeId) {
     364             :     case TypeId::kI8:
     365             :     case TypeId::kU8:
     366             :       imm.truncateTo8Bits();
     367             :       ASMJIT_FALLTHROUGH;
     368             : 
     369           0 :     case TypeId::kI16:
     370             :     case TypeId::kU16:
     371             :       imm.truncateTo16Bits();
     372             :       ASMJIT_FALLTHROUGH;
     373             : 
     374           0 :     case TypeId::kI32:
     375             :     case TypeId::kU32:
     376             :     case TypeId::kF32:
     377             :       mem.setSize(4);
     378             :       imm.truncateTo32Bits();
     379           0 :       cc()->emit(X86Inst::kIdMov, mem, imm);
     380           0 :       break;
     381             : 
     382           0 :     case TypeId::kI64:
     383             :     case TypeId::kU64:
     384             :     case TypeId::kF64:
     385             :     case TypeId::kMmx32:
     386             :     case TypeId::kMmx64:
     387           0 :       if (gpSize == 4) {
     388             :         uint32_t hi = imm.getUInt32Hi();
     389             : 
     390             :         // Lo-Part.
     391             :         mem.setSize(4);
     392             :         imm.truncateTo32Bits();
     393             : 
     394           0 :         cc()->emit(X86Inst::kIdMov, mem, imm);
     395             :         mem.addOffsetLo32(gpSize);
     396             : 
     397             :         // Hi-Part.
     398             :         imm.setUInt32(hi);
     399           0 :         cc()->emit(X86Inst::kIdMov, mem, imm);
     400             :       }
     401             :       else {
     402             :         mem.setSize(8);
     403           0 :         cc()->emit(X86Inst::kIdMov, mem, imm);
     404             :       }
     405             :       break;
     406             : 
     407             :     default:
     408             :       return DebugUtils::errored(kErrorInvalidState);
     409             :   }
     410             : 
     411             :   return kErrorOk;
     412             : }
     413             : 
     414           0 : Error X86RAPass::emitRegToStack(uint32_t dstTypeId, const X86Mem* dst, uint32_t srcTypeId, uint32_t srcPhysId) noexcept {
     415             :   ASMJIT_ASSERT(srcPhysId != Globals::kInvalidRegId);
     416             : 
     417             :   X86Mem m0(*dst);
     418             :   X86Reg r0, r1;
     419             : 
     420             :   uint32_t gpSize = cc()->getGpSize();
     421             :   uint32_t instId = 0;
     422             : 
     423           0 :   switch (dstTypeId) {
     424             :     case TypeId::kI64:
     425             :     case TypeId::kU64:
     426             :       // Extend BYTE->QWORD (GP).
     427           0 :       if (TypeId::isGpb(srcTypeId)) {
     428             :         r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
     429             : 
     430           0 :         instId = (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI8) ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
     431           0 :         goto _ExtendMovGpXQ;
     432             :       }
     433             : 
     434             :       // Extend WORD->QWORD (GP).
     435             :       if (TypeId::isGpw(srcTypeId)) {
     436             :         r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
     437             : 
     438           0 :         instId = (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI16) ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
     439           0 :         goto _ExtendMovGpXQ;
     440             :       }
     441             : 
     442             :       // Extend DWORD->QWORD (GP).
     443             :       if (TypeId::isGpd(srcTypeId)) {
     444             :         r1.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
     445             : 
     446             :         instId = X86Inst::kIdMovsxd;
     447           0 :         if (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI32)
     448           0 :           goto _ExtendMovGpXQ;
     449             :         else
     450           0 :           goto _ZeroExtendGpDQ;
     451             :       }
     452             : 
     453             :       // Move QWORD (GP).
     454           0 :       if (TypeId::isGpq(srcTypeId)) goto MovGpQ;
     455           0 :       if (TypeId::isMmx(srcTypeId)) goto MovMmQ;
     456           0 :       if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
     457             :       break;
     458             : 
     459             :     case TypeId::kI32:
     460             :     case TypeId::kU32:
     461             :     case TypeId::kI16:
     462             :     case TypeId::kU16:
     463             :       // DWORD <- WORD (Zero|Sign Extend).
     464           0 :       if (TypeId::isGpw(srcTypeId)) {
     465           0 :         bool isDstSigned = dstTypeId == TypeId::kI16 || dstTypeId == TypeId::kI32;
     466           0 :         bool isSrcSigned = srcTypeId == TypeId::kI8  || srcTypeId == TypeId::kI16;
     467             : 
     468             :         r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
     469           0 :         instId = isDstSigned && isSrcSigned ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
     470           0 :         goto _ExtendMovGpD;
     471             :       }
     472             : 
     473             :       // DWORD <- BYTE (Zero|Sign Extend).
     474           0 :       if (TypeId::isGpb(srcTypeId)) {
     475           0 :         bool isDstSigned = dstTypeId == TypeId::kI16 || dstTypeId == TypeId::kI32;
     476           0 :         bool isSrcSigned = srcTypeId == TypeId::kI8  || srcTypeId == TypeId::kI16;
     477             : 
     478             :         r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
     479           0 :         instId = isDstSigned && isSrcSigned ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
     480           0 :         goto _ExtendMovGpD;
     481             :       }
     482             :       ASMJIT_FALLTHROUGH;
     483             : 
     484             :     case TypeId::kI8:
     485             :     case TypeId::kU8:
     486           0 :       if (TypeId::isInt(srcTypeId)) goto MovGpD;
     487           0 :       if (TypeId::isMmx(srcTypeId)) goto MovMmD;
     488           0 :       if (TypeId::isVec(srcTypeId)) goto MovXmmD;
     489             :       break;
     490             : 
     491             :     case TypeId::kMmx32:
     492             :     case TypeId::kMmx64:
     493             :       // Extend BYTE->QWORD (GP).
     494           0 :       if (TypeId::isGpb(srcTypeId)) {
     495             :         r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
     496             : 
     497             :         instId = X86Inst::kIdMovzx;
     498           0 :         goto _ExtendMovGpXQ;
     499             :       }
     500             : 
     501             :       // Extend WORD->QWORD (GP).
     502             :       if (TypeId::isGpw(srcTypeId)) {
     503             :         r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
     504             : 
     505             :         instId = X86Inst::kIdMovzx;
     506           0 :         goto _ExtendMovGpXQ;
     507             :       }
     508             : 
     509           0 :       if (TypeId::isGpd(srcTypeId)) goto _ExtendMovGpDQ;
     510           0 :       if (TypeId::isGpq(srcTypeId)) goto MovGpQ;
     511           0 :       if (TypeId::isMmx(srcTypeId)) goto MovMmQ;
     512           0 :       if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
     513             :       break;
     514             : 
     515             :     case TypeId::kF32:
     516             :     case TypeId::kF32x1:
     517           0 :       if (TypeId::isVec(srcTypeId)) goto MovXmmD;
     518             :       break;
     519             : 
     520             :     case TypeId::kF64:
     521             :     case TypeId::kF64x1:
     522           0 :       if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
     523             :       break;
     524             : 
     525             :     default:
     526             :       // TODO: Vector types by stack.
     527             :       break;
     528             :   }
     529             :   return DebugUtils::errored(kErrorInvalidState);
     530             : 
     531             :   // Extend+Move Gp.
     532           0 : _ExtendMovGpD:
     533             :   m0.setSize(4);
     534             :   r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
     535             : 
     536           0 :   cc()->emit(instId, r0, r1);
     537           0 :   cc()->emit(X86Inst::kIdMov, m0, r0);
     538           0 :   return kErrorOk;
     539             : 
     540           0 : _ExtendMovGpXQ:
     541           0 :   if (gpSize == 8) {
     542             :     m0.setSize(8);
     543             :     r0.setX86RegT<X86Reg::kRegGpq>(srcPhysId);
     544             : 
     545           0 :     cc()->emit(instId, r0, r1);
     546           0 :     cc()->emit(X86Inst::kIdMov, m0, r0);
     547             :   }
     548             :   else {
     549             :     m0.setSize(4);
     550             :     r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
     551             : 
     552           0 :     cc()->emit(instId, r0, r1);
     553             : 
     554           0 : _ExtendMovGpDQ:
     555           0 :     cc()->emit(X86Inst::kIdMov, m0, r0);
     556             :     m0.addOffsetLo32(4);
     557           0 :     cc()->emit(X86Inst::kIdAnd, m0, 0);
     558             :   }
     559             :   return kErrorOk;
     560             : 
     561             : _ZeroExtendGpDQ:
     562             :   m0.setSize(4);
     563             :   r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
     564           0 :   goto _ExtendMovGpDQ;
     565             : 
     566             :   // Move Gp.
     567             : MovGpD:
     568             :   m0.setSize(4);
     569             :   r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
     570           0 :   return cc()->emit(X86Inst::kIdMov, m0, r0);
     571             : 
     572           0 : MovGpQ:
     573             :   m0.setSize(8);
     574             :   r0.setX86RegT<X86Reg::kRegGpq>(srcPhysId);
     575           0 :   return cc()->emit(X86Inst::kIdMov, m0, r0);
     576             : 
     577             :   // Move Mm.
     578             : MovMmD:
     579             :   m0.setSize(4);
     580             :   r0.setX86RegT<X86Reg::kRegMm>(srcPhysId);
     581           0 :   return cc()->emit(X86Inst::kIdMovd, m0, r0);
     582             : 
     583           0 : MovMmQ:
     584             :   m0.setSize(8);
     585             :   r0.setX86RegT<X86Reg::kRegMm>(srcPhysId);
     586           0 :   return cc()->emit(X86Inst::kIdMovq, m0, r0);
     587             : 
     588             :   // Move XMM.
     589           0 : MovXmmD:
     590             :   m0.setSize(4);
     591             :   r0.setX86RegT<X86Reg::kRegXmm>(srcPhysId);
     592           0 :   return cc()->emit(X86Inst::kIdMovss, m0, r0);
     593             : 
     594           0 : MovXmmQ:
     595             :   m0.setSize(8);
     596             :   r0.setX86RegT<X86Reg::kRegXmm>(srcPhysId);
     597           0 :   return cc()->emit(X86Inst::kIdMovlps, m0, r0);
     598             : }
     599             : 
     600             : // ============================================================================
     601             : // [asmjit::X86RAPass - Register Management]
     602             : // ============================================================================
     603             : 
     604             : #if defined(ASMJIT_DEBUG)
     605             : template<int C>
     606             : static ASMJIT_INLINE void X86RAPass_checkStateVars(X86RAPass* self) {
     607             :   X86RAState* state = self->getState();
     608             :   VirtReg** sVars = state->getListByKind(C);
     609             : 
     610             :   uint32_t physId;
     611             :   uint32_t regMask;
     612             :   uint32_t regCount = self->_regCount.get(C);
     613             : 
     614             :   uint32_t occupied = state->_occupied.get(C);
     615             :   uint32_t modified = state->_modified.get(C);
     616             : 
     617             :   for (physId = 0, regMask = 1; physId < regCount; physId++, regMask <<= 1) {
     618             :     VirtReg* vreg = sVars[physId];
     619             : 
     620             :     if (!vreg) {
     621             :       ASMJIT_ASSERT((occupied & regMask) == 0);
     622             :       ASMJIT_ASSERT((modified & regMask) == 0);
     623             :     }
     624             :     else {
     625             :       ASMJIT_ASSERT((occupied & regMask) != 0);
     626             :       ASMJIT_ASSERT((modified & regMask) == (static_cast<uint32_t>(vreg->isModified()) << physId));
     627             : 
     628             :       ASMJIT_ASSERT(vreg->getKind() == C);
     629             :       ASMJIT_ASSERT(vreg->getState() == VirtReg::kStateReg);
     630             :       ASMJIT_ASSERT(vreg->getPhysId() == physId);
     631             :     }
     632             :   }
     633             : }
     634             : 
     635             : void X86RAPass::_checkState() {
     636             :   X86RAPass_checkStateVars<X86Reg::kKindGp >(this);
     637             :   X86RAPass_checkStateVars<X86Reg::kKindMm >(this);
     638             :   X86RAPass_checkStateVars<X86Reg::kKindVec>(this);
     639             : }
     640             : #else
     641           0 : void X86RAPass::_checkState() {}
     642             : #endif // ASMJIT_DEBUG
     643             : 
     644             : // ============================================================================
     645             : // [asmjit::X86RAPass - State - Load]
     646             : // ============================================================================
     647             : 
     648             : template<int C>
     649             : static ASMJIT_INLINE void X86RAPass_loadStateVars(X86RAPass* self, X86RAState* src) {
     650             :   X86RAState* cur = self->getState();
     651             : 
     652             :   VirtReg** cVars = cur->getListByKind(C);
     653             :   VirtReg** sVars = src->getListByKind(C);
     654             : 
     655             :   uint32_t physId;
     656             :   uint32_t modified = src->_modified.get(C);
     657             :   uint32_t regCount = self->_regCount.get(C);
     658             : 
     659           0 :   for (physId = 0; physId < regCount; physId++, modified >>= 1) {
     660           0 :     VirtReg* vreg = sVars[physId];
     661           0 :     cVars[physId] = vreg;
     662           0 :     if (!vreg) continue;
     663             : 
     664             :     vreg->setState(VirtReg::kStateReg);
     665             :     vreg->setPhysId(physId);
     666           0 :     vreg->setModified(modified & 0x1);
     667             :   }
     668             : }
     669             : 
     670           0 : void X86RAPass::loadState(RAState* src_) {
     671             :   X86RAState* cur = getState();
     672             :   X86RAState* src = static_cast<X86RAState*>(src_);
     673             : 
     674             :   VirtReg** vregs = _contextVd.getData();
     675           0 :   uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
     676             : 
     677             :   // Load allocated variables.
     678             :   X86RAPass_loadStateVars<X86Reg::kKindGp >(this, src);
     679             :   X86RAPass_loadStateVars<X86Reg::kKindMm >(this, src);
     680             :   X86RAPass_loadStateVars<X86Reg::kKindVec>(this, src);
     681             : 
     682             :   // Load masks.
     683           0 :   cur->_occupied = src->_occupied;
     684           0 :   cur->_modified = src->_modified;
     685             : 
     686             :   // Load states of other variables and clear their 'Modified' flags.
     687           0 :   for (uint32_t i = 0; i < count; i++) {
     688             :     uint32_t vState = src->_cells[i].getState();
     689             : 
     690           0 :     if (vState == VirtReg::kStateReg)
     691           0 :       continue;
     692             : 
     693           0 :     vregs[i]->setState(vState);
     694           0 :     vregs[i]->setPhysId(Globals::kInvalidRegId);
     695           0 :     vregs[i]->setModified(false);
     696             :   }
     697             : 
     698             :   ASMJIT_X86_CHECK_STATE
     699           0 : }
     700             : 
     701             : // ============================================================================
     702             : // [asmjit::X86RAPass - State - Save]
     703             : // ============================================================================
     704             : 
     705           0 : RAState* X86RAPass::saveState() {
     706             :   VirtReg** vregs = _contextVd.getData();
     707           0 :   uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
     708             : 
     709             :   size_t size = Utils::alignTo<size_t>(
     710             :     sizeof(X86RAState) + count * sizeof(X86StateCell), sizeof(void*));
     711             : 
     712             :   X86RAState* cur = getState();
     713           0 :   X86RAState* dst = _zone->allocT<X86RAState>(size);
     714           0 :   if (!dst) return nullptr;
     715             : 
     716             :   // Store links.
     717           0 :   ::memcpy(dst->_list, cur->_list, X86RAState::kAllCount * sizeof(VirtReg*));
     718             : 
     719             :   // Store masks.
     720           0 :   dst->_occupied = cur->_occupied;
     721           0 :   dst->_modified = cur->_modified;
     722             : 
     723             :   // Store cells.
     724           0 :   for (uint32_t i = 0; i < count; i++) {
     725           0 :     VirtReg* vreg = static_cast<VirtReg*>(vregs[i]);
     726             :     X86StateCell& cell = dst->_cells[i];
     727             : 
     728             :     cell.reset();
     729             :     cell.setState(vreg->getState());
     730             :   }
     731             : 
     732             :   return dst;
     733             : }
     734             : 
     735             : // ============================================================================
     736             : // [asmjit::X86RAPass - State - Switch]
     737             : // ============================================================================
     738             : 
     739             : template<int C>
     740             : static ASMJIT_INLINE void X86RAPass_switchStateVars(X86RAPass* self, X86RAState* src) {
     741             :   X86RAState* dst = self->getState();
     742             : 
     743             :   VirtReg** dVars = dst->getListByKind(C);
     744             :   VirtReg** sVars = src->getListByKind(C);
     745             : 
     746           0 :   X86StateCell* cells = src->_cells;
     747             :   uint32_t regCount = self->_regCount.get(C);
     748             :   bool didWork;
     749             : 
     750           0 :   do {
     751             :     didWork = false;
     752             : 
     753           0 :     for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
     754           0 :       VirtReg* dVReg = dVars[physId];
     755           0 :       VirtReg* sVd = sVars[physId];
     756           0 :       if (dVReg == sVd) continue;
     757             : 
     758           0 :       if (dVReg) {
     759           0 :         const X86StateCell& cell = cells[dVReg->_raId];
     760             : 
     761           0 :         if (cell.getState() != VirtReg::kStateReg) {
     762           0 :           if (cell.getState() == VirtReg::kStateMem)
     763             :             self->spill<C>(dVReg);
     764             :           else
     765             :             self->unuse<C>(dVReg);
     766             : 
     767             :           dVReg = nullptr;
     768             :           didWork = true;
     769           0 :           if (!sVd) continue;
     770             :         }
     771             :       }
     772             : 
     773           0 :       if (!dVReg && sVd) {
     774           0 : _MoveOrLoad:
     775           0 :         if (sVd->getPhysId() != Globals::kInvalidRegId)
     776             :           self->move<C>(sVd, physId);
     777             :         else
     778             :           self->load<C>(sVd, physId);
     779             : 
     780             :         didWork = true;
     781           0 :         continue;
     782             :       }
     783             : 
     784           0 :       if (dVReg) {
     785           0 :         const X86StateCell& cell = cells[dVReg->_raId];
     786           0 :         if (!sVd) {
     787           0 :           if (cell.getState() == VirtReg::kStateReg)
     788           0 :             continue;
     789             : 
     790           0 :           if (cell.getState() == VirtReg::kStateMem)
     791             :             self->spill<C>(dVReg);
     792             :           else
     793             :             self->unuse<C>(dVReg);
     794             : 
     795             :           didWork = true;
     796           0 :           continue;
     797             :         }
     798             :         else {
     799           0 :           if (cell.getState() == VirtReg::kStateReg) {
     800           0 :             if (dVReg->getPhysId() != Globals::kInvalidRegId && sVd->getPhysId() != Globals::kInvalidRegId) {
     801             :               if (C == X86Reg::kKindGp) {
     802             :                 self->swapGp(dVReg, sVd);
     803             :               }
     804             :               else {
     805             :                 self->spill<C>(dVReg);
     806             :                 self->move<C>(sVd, physId);
     807             :               }
     808             : 
     809             :               didWork = true;
     810           0 :               continue;
     811             :             }
     812             :             else {
     813             :               didWork = true;
     814           0 :               continue;
     815             :             }
     816             :           }
     817             : 
     818           0 :           if (cell.getState() == VirtReg::kStateMem)
     819             :             self->spill<C>(dVReg);
     820             :           else
     821             :             self->unuse<C>(dVReg);
     822           0 :           goto _MoveOrLoad;
     823             :         }
     824             :       }
     825             :     }
     826             :   } while (didWork);
     827             : 
     828             :   uint32_t dModified = dst->_modified.get(C);
     829             :   uint32_t sModified = src->_modified.get(C);
     830             : 
     831           0 :   if (dModified != sModified) {
     832           0 :     for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
     833           0 :       VirtReg* vreg = dVars[physId];
     834           0 :       if (!vreg) continue;
     835             : 
     836           0 :       if ((dModified & regMask) && !(sModified & regMask)) {
     837             :         self->save<C>(vreg);
     838           0 :         continue;
     839             :       }
     840             : 
     841           0 :       if (!(dModified & regMask) && (sModified & regMask)) {
     842             :         self->modify<C>(vreg);
     843           0 :         continue;
     844             :       }
     845             :     }
     846             :   }
     847             : }
     848             : 
     849           0 : void X86RAPass::switchState(RAState* src_) {
     850             :   ASMJIT_ASSERT(src_ != nullptr);
     851             : 
     852             :   X86RAState* cur = getState();
     853             :   X86RAState* src = static_cast<X86RAState*>(src_);
     854             : 
     855             :   // Ignore if both states are equal.
     856           0 :   if (cur == src)
     857             :     return;
     858             : 
     859             :   // Switch variables.
     860             :   X86RAPass_switchStateVars<X86Reg::kKindGp >(this, src);
     861             :   X86RAPass_switchStateVars<X86Reg::kKindMm >(this, src);
     862             :   X86RAPass_switchStateVars<X86Reg::kKindVec>(this, src);
     863             : 
     864             :   // Calculate changed state.
     865             :   VirtReg** vregs = _contextVd.getData();
     866           0 :   uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
     867             : 
     868             :   X86StateCell* cells = src->_cells;
     869           0 :   for (uint32_t i = 0; i < count; i++) {
     870           0 :     VirtReg* vreg = static_cast<VirtReg*>(vregs[i]);
     871           0 :     const X86StateCell& cell = cells[i];
     872             :     uint32_t vState = cell.getState();
     873             : 
     874           0 :     if (vState != VirtReg::kStateReg) {
     875             :       vreg->setState(vState);
     876             :       vreg->setModified(false);
     877             :     }
     878             :   }
     879             : 
     880             :   ASMJIT_X86_CHECK_STATE
     881             : }
     882             : 
     883             : // ============================================================================
     884             : // [asmjit::X86RAPass - State - Intersect]
     885             : // ============================================================================
     886             : 
     887             : // The algorithm is actually not so smart, but tries to find an intersection od
     888             : // `a` and `b` and tries to move/alloc a variable into that location if it's
     889             : // possible. It also finds out which variables will be spilled/unused  by `a`
     890             : // and `b` and performs that action here. It may improve the switch state code
     891             : // in certain cases, but doesn't necessarily do the best job possible.
     892             : template<int C>
     893             : static ASMJIT_INLINE void X86RAPass_intersectStateVars(X86RAPass* self, X86RAState* a, X86RAState* b) {
     894             :   X86RAState* dst = self->getState();
     895             : 
     896             :   VirtReg** dVars = dst->getListByKind(C);
     897             :   VirtReg** aVars = a->getListByKind(C);
     898             : 
     899           0 :   X86StateCell* aCells = a->_cells;
     900           0 :   X86StateCell* bCells = b->_cells;
     901             : 
     902             :   uint32_t regCount = self->_regCount.get(C);
     903             :   bool didWork;
     904             : 
     905             :   // Similar to `switchStateVars()`, we iterate over and over until there is
     906             :   // no work to be done.
     907           0 :   do {
     908             :     didWork = false;
     909             : 
     910           0 :     for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
     911           0 :       VirtReg* dVReg = dVars[physId]; // Destination reg.
     912           0 :       VirtReg* aVReg = aVars[physId]; // State-a reg.
     913             : 
     914           0 :       if (dVReg == aVReg) continue;
     915             : 
     916           0 :       if (dVReg) {
     917           0 :         const X86StateCell& aCell = aCells[dVReg->_raId];
     918           0 :         const X86StateCell& bCell = bCells[dVReg->_raId];
     919             : 
     920           0 :         if (aCell.getState() != VirtReg::kStateReg && bCell.getState() != VirtReg::kStateReg) {
     921           0 :           if (aCell.getState() == VirtReg::kStateMem || bCell.getState() == VirtReg::kStateMem)
     922             :             self->spill<C>(dVReg);
     923             :           else
     924             :             self->unuse<C>(dVReg);
     925             : 
     926             :           dVReg = nullptr;
     927             :           didWork = true;
     928           0 :           if (!aVReg) continue;
     929             :         }
     930             :       }
     931             : 
     932           0 :       if (!dVReg && aVReg) {
     933           0 :         if (aVReg->getPhysId() != Globals::kInvalidRegId)
     934             :           self->move<C>(aVReg, physId);
     935             :         else
     936             :           self->load<C>(aVReg, physId);
     937             : 
     938             :         didWork = true;
     939           0 :         continue;
     940             :       }
     941             : 
     942           0 :       if (dVReg) {
     943           0 :         const X86StateCell& aCell = aCells[dVReg->_raId];
     944           0 :         const X86StateCell& bCell = bCells[dVReg->_raId];
     945             : 
     946           0 :         if (!aVReg) {
     947           0 :           if (aCell.getState() == VirtReg::kStateReg || bCell.getState() == VirtReg::kStateReg)
     948           0 :             continue;
     949             : 
     950           0 :           if (aCell.getState() == VirtReg::kStateMem || bCell.getState() == VirtReg::kStateMem)
     951             :             self->spill<C>(dVReg);
     952             :           else
     953             :             self->unuse<C>(dVReg);
     954             : 
     955             :           didWork = true;
     956           0 :           continue;
     957             :         }
     958             :         else if (C == X86Reg::kKindGp) {
     959           0 :           if (aCell.getState() == VirtReg::kStateReg) {
     960           0 :             if (dVReg->getPhysId() != Globals::kInvalidRegId && aVReg->getPhysId() != Globals::kInvalidRegId) {
     961             :               self->swapGp(dVReg, aVReg);
     962             : 
     963             :               didWork = true;
     964           0 :               continue;
     965             :             }
     966             :           }
     967             :         }
     968             :       }
     969             :     }
     970             :   } while (didWork);
     971             : 
     972             :   uint32_t dModified = dst->_modified.get(C);
     973             :   uint32_t aModified = a->_modified.get(C);
     974             : 
     975           0 :   if (dModified != aModified) {
     976           0 :     for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
     977           0 :       VirtReg* vreg = dVars[physId];
     978           0 :       if (!vreg) continue;
     979             : 
     980           0 :       const X86StateCell& aCell = aCells[vreg->_raId];
     981           0 :       if ((dModified & regMask) && !(aModified & regMask) && aCell.getState() == VirtReg::kStateReg)
     982             :         self->save<C>(vreg);
     983             :     }
     984             :   }
     985             : }
     986             : 
     987           0 : void X86RAPass::intersectStates(RAState* a_, RAState* b_) {
     988             :   X86RAState* a = static_cast<X86RAState*>(a_);
     989             :   X86RAState* b = static_cast<X86RAState*>(b_);
     990             : 
     991             :   ASMJIT_ASSERT(a != nullptr);
     992             :   ASMJIT_ASSERT(b != nullptr);
     993             : 
     994             :   X86RAPass_intersectStateVars<X86Reg::kKindGp >(this, a, b);
     995             :   X86RAPass_intersectStateVars<X86Reg::kKindMm >(this, a, b);
     996             :   X86RAPass_intersectStateVars<X86Reg::kKindVec>(this, a, b);
     997             : 
     998             :   ASMJIT_X86_CHECK_STATE
     999           0 : }
    1000             : 
    1001             : // ============================================================================
    1002             : // [asmjit::X86RAPass - GetJccFlow / GetOppositeJccFlow]
    1003             : // ============================================================================
    1004             : 
    1005             : //! \internal
    1006             : static ASMJIT_INLINE CBNode* X86RAPass_getJccFlow(CBJump* jNode) {
    1007           0 :   if (jNode->isTaken())
    1008           0 :     return jNode->getTarget();
    1009             :   else
    1010           0 :     return jNode->getNext();
    1011             : }
    1012             : 
    1013             : //! \internal
    1014             : static ASMJIT_INLINE CBNode* X86RAPass_getOppositeJccFlow(CBJump* jNode) {
    1015           0 :   if (jNode->isTaken())
    1016           0 :     return jNode->getNext();
    1017             :   else
    1018           0 :     return jNode->getTarget();
    1019             : }
    1020             : 
    1021             : // ============================================================================
    1022             : // [asmjit::X86RAPass - SingleVarInst]
    1023             : // ============================================================================
    1024             : 
    1025             : //! \internal
    1026         252 : static void X86RAPass_prepareSingleVarInst(uint32_t instId, TiedReg* tr) {
    1027         252 :   switch (instId) {
    1028             :     // - andn     reg, reg ; Set all bits in reg to 0.
    1029             :     // - xor/pxor reg, reg ; Set all bits in reg to 0.
    1030             :     // - sub/psub reg, reg ; Set all bits in reg to 0.
    1031             :     // - pcmpgt   reg, reg ; Set all bits in reg to 0.
    1032             :     // - pcmpeq   reg, reg ; Set all bits in reg to 1.
    1033         252 :     case X86Inst::kIdPandn     :
    1034             :     case X86Inst::kIdXor       : case X86Inst::kIdXorpd     : case X86Inst::kIdXorps     : case X86Inst::kIdPxor      :
    1035             :     case X86Inst::kIdSub:
    1036             :     case X86Inst::kIdPsubb     : case X86Inst::kIdPsubw     : case X86Inst::kIdPsubd     : case X86Inst::kIdPsubq     :
    1037             :     case X86Inst::kIdPsubsb    : case X86Inst::kIdPsubsw    : case X86Inst::kIdPsubusb   : case X86Inst::kIdPsubusw   :
    1038             :     case X86Inst::kIdPcmpeqb   : case X86Inst::kIdPcmpeqw   : case X86Inst::kIdPcmpeqd   : case X86Inst::kIdPcmpeqq   :
    1039             :     case X86Inst::kIdPcmpgtb   : case X86Inst::kIdPcmpgtw   : case X86Inst::kIdPcmpgtd   : case X86Inst::kIdPcmpgtq   :
    1040         252 :       tr->flags &= ~TiedReg::kRReg;
    1041         252 :       break;
    1042             : 
    1043             :     // - and      reg, reg ; Nop.
    1044             :     // - or       reg, reg ; Nop.
    1045             :     // - xchg     reg, reg ; Nop.
    1046           0 :     case X86Inst::kIdAnd       : case X86Inst::kIdAndpd     : case X86Inst::kIdAndps     : case X86Inst::kIdPand      :
    1047             :     case X86Inst::kIdOr        : case X86Inst::kIdOrpd      : case X86Inst::kIdOrps      : case X86Inst::kIdPor       :
    1048             :     case X86Inst::kIdXchg      :
    1049           0 :       tr->flags &= ~TiedReg::kWReg;
    1050           0 :       break;
    1051             :   }
    1052         252 : }
    1053             : 
    1054             : // ============================================================================
    1055             : // [asmjit::X86RAPass - Helpers]
    1056             : // ============================================================================
    1057             : 
    1058        1944 : static void X86RAPass_assignStackArgsRegId(X86RAPass* self, CCFunc* func) {
    1059             :   const FuncDetail& fd = func->getDetail();
    1060             :   FuncFrameInfo& ffi = func->getFrameInfo();
    1061             : 
    1062             :   // Select some register which will contain the base address of function
    1063             :   // arguments and return address. The algorithm tries to select registers
    1064             :   // which are saved or not preserved by default, if not successful it picks
    1065             :   // any other register and adds it to `_savedRegs`.
    1066             :   uint32_t stackArgsRegId;
    1067        1944 :   if (ffi.hasPreservedFP()) {
    1068             :     stackArgsRegId = X86Gp::kIdBp;
    1069             :   }
    1070             :   else {
    1071             :     // Passed registers as defined by the calling convention.
    1072             :     uint32_t passed = fd.getPassedRegs(X86Reg::kKindGp);
    1073             : 
    1074             :     // Registers actually used to pass function arguments (related to this
    1075             :     // function signature) with ESP|RSP included as this register can't be
    1076             :     // used in general to hold anything bug stack pointer.
    1077        1944 :     uint32_t used = fd.getUsedRegs(X86Reg::kKindGp) | Utils::mask(X86Gp::kIdSp);
    1078             : 
    1079             :     // First try register that is defined to pass a function argument by the
    1080             :     // calling convention, but is not used by this function. This will most
    1081             :     // likely fail in 32-bit mode, but there is a high chance that it will
    1082             :     // pass in 64-bit mode if the function doesn't use so many arguments.
    1083        1944 :     uint32_t regs = passed & ~used;
    1084             : 
    1085             :     // Pick any other register if that didn't work out.
    1086        1944 :     if (!regs) regs = ~passed & ~used;
    1087             : 
    1088             :     stackArgsRegId = Utils::findFirstBit(regs);
    1089             :     ASMJIT_ASSERT(stackArgsRegId < self->cc()->getGpCount());
    1090             :   }
    1091             : 
    1092             :   ffi.setStackArgsRegId(stackArgsRegId);
    1093        1944 : }
    1094             : 
    1095             : // ============================================================================
    1096             : // [asmjit::X86RAPass - SArg Insertion]
    1097             : // ============================================================================
    1098             : 
    1099             : struct SArgData {
    1100             :   VirtReg* sVd;
    1101             :   VirtReg* cVd;
    1102             :   CCPushArg* sArg;
    1103             :   uint32_t aType;
    1104             : };
    1105             : 
    1106             : static ASMJIT_INLINE bool X86RAPass_mustConvertSArg(X86RAPass* self, uint32_t dstTypeId, uint32_t srcTypeId) noexcept{
    1107           0 :   uint32_t dstFloatSize = dstTypeId == TypeId::kF32   ? 4 :
    1108             :                           dstTypeId == TypeId::kF64   ? 8 : 0;
    1109             : 
    1110           0 :   uint32_t srcFloatSize = srcTypeId == TypeId::kF32   ? 4 :
    1111             :                           srcTypeId == TypeId::kF32x1 ? 4 :
    1112             :                           srcTypeId == TypeId::kF64   ? 8 :
    1113             :                           srcTypeId == TypeId::kF64x1 ? 8 : 0;
    1114             : 
    1115           0 :   if (dstFloatSize && srcFloatSize)
    1116             :     return dstFloatSize != srcFloatSize;
    1117             :   else
    1118             :     return false;
    1119             : }
    1120             : 
    1121             : static ASMJIT_INLINE uint32_t X86RAPass_typeOfConvertedSArg(X86RAPass* self, uint32_t dstTypeId, uint32_t srcTypeId) noexcept {
    1122             :   ASMJIT_ASSERT(X86RAPass_mustConvertSArg(self, dstTypeId, srcTypeId));
    1123           0 :   return dstTypeId == TypeId::kF32 ? TypeId::kF32x1 : TypeId::kF64x1;
    1124             : }
    1125             : 
    1126             : static ASMJIT_INLINE Error X86RAPass_insertPushArg(
    1127             :   X86RAPass* self, CCFuncCall* call,
    1128             :   VirtReg* sReg, const uint32_t* gaRegs,
    1129             :   const FuncDetail::Value& arg, uint32_t argIndex,
    1130             :   SArgData* sArgList, uint32_t& sArgCount) {
    1131             : 
    1132             :   X86Compiler* cc = self->cc();
    1133             :   uint32_t i;
    1134             :   uint32_t dstTypeId = arg.getTypeId();
    1135             :   uint32_t srcTypeId = sReg->getTypeId();
    1136             : 
    1137             :   // First locate or create sArgBase.
    1138           0 :   for (i = 0; i < sArgCount; i++)
    1139           0 :     if (sArgList[i].sVd == sReg && !sArgList[i].cVd)
    1140             :       break;
    1141             : 
    1142           0 :   SArgData* sArgData = &sArgList[i];
    1143           0 :   if (i == sArgCount) {
    1144           0 :     sArgData->sVd = sReg;
    1145           0 :     sArgData->cVd = nullptr;
    1146           0 :     sArgData->sArg = nullptr;
    1147           0 :     sArgData->aType = 0xFF;
    1148           0 :     sArgCount++;
    1149             :   }
    1150             : 
    1151             :   uint32_t srcRegKind = sReg->getKind();
    1152             : 
    1153             :   // Only handles float<->double conversion.
    1154           0 :   if (X86RAPass_mustConvertSArg(self, dstTypeId, srcTypeId)) {
    1155             :     uint32_t cvtTypeId = X86RAPass_typeOfConvertedSArg(self, dstTypeId, srcTypeId);
    1156             :     uint32_t cvtRegKind = X86Reg::kKindVec;
    1157             : 
    1158           0 :     while (++i < sArgCount) {
    1159           0 :       sArgData = &sArgList[i];
    1160           0 :       if (sArgData->sVd != sReg)
    1161             :         break;
    1162             : 
    1163           0 :       if (sArgData->cVd->getTypeId() != cvtTypeId || sArgData->aType != dstTypeId)
    1164           0 :         continue;
    1165             : 
    1166           0 :       sArgData->sArg->_args |= Utils::mask(argIndex);
    1167             :       return kErrorOk;
    1168             :     }
    1169             : 
    1170           0 :     VirtReg* cReg = cc->newVirtReg(dstTypeId, x86OpData.archRegs.regInfo[X86Reg::kRegXmm].getSignature(), nullptr);
    1171           0 :     if (!cReg) return DebugUtils::errored(kErrorNoHeapMemory);
    1172             : 
    1173             :     CCPushArg* sArg = cc->newNodeT<CCPushArg>(call, sReg, cReg);
    1174           0 :     if (!sArg) return DebugUtils::errored(kErrorNoHeapMemory);
    1175             : 
    1176             :     X86RAData* raData = self->newRAData(2);
    1177           0 :     if (!raData) return DebugUtils::errored(kErrorNoHeapMemory);
    1178             : 
    1179           0 :     ASMJIT_PROPAGATE(self->assignRAId(cReg));
    1180           0 :     ASMJIT_PROPAGATE(self->assignRAId(sReg));
    1181             : 
    1182           0 :     raData->tiedTotal = 2;
    1183             :     raData->tiedCount.reset();
    1184             :     raData->tiedCount.add(srcRegKind);
    1185             :     raData->tiedCount.add(cvtRegKind);
    1186             : 
    1187             :     raData->tiedIndex.reset();
    1188             :     raData->inRegs.reset();
    1189             :     raData->outRegs.reset();
    1190             :     raData->clobberedRegs.reset();
    1191             : 
    1192           0 :     if (srcRegKind <= cvtRegKind) {
    1193           0 :       raData->tiedArray[0].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
    1194           0 :       raData->tiedArray[1].init(cReg, TiedReg::kWReg, 0, gaRegs[cvtRegKind]);
    1195           0 :       raData->tiedIndex.set(cvtRegKind, srcRegKind != cvtRegKind);
    1196             :     }
    1197             :     else {
    1198           0 :       raData->tiedArray[0].init(cReg, TiedReg::kWReg, 0, gaRegs[cvtRegKind]);
    1199           0 :       raData->tiedArray[1].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
    1200             :       raData->tiedIndex.set(srcRegKind, 1);
    1201             :     }
    1202             : 
    1203             :     sArg->setPassData(raData);
    1204           0 :     sArg->_args |= Utils::mask(argIndex);
    1205             : 
    1206           0 :     cc->addBefore(sArg, call);
    1207           0 :     ::memmove(sArgData + 1, sArgData, (sArgCount - i) * sizeof(SArgData));
    1208             : 
    1209           0 :     sArgData->sVd = sReg;
    1210           0 :     sArgData->cVd = cReg;
    1211           0 :     sArgData->sArg = sArg;
    1212           0 :     sArgData->aType = dstTypeId;
    1213             : 
    1214           0 :     sArgCount++;
    1215             :     return kErrorOk;
    1216             :   }
    1217             :   else {
    1218           0 :     CCPushArg* sArg = sArgData->sArg;
    1219           0 :     ASMJIT_PROPAGATE(self->assignRAId(sReg));
    1220             : 
    1221           0 :     if (!sArg) {
    1222             :       sArg = cc->newNodeT<CCPushArg>(call, sReg, (VirtReg*)nullptr);
    1223           0 :       if (!sArg) return DebugUtils::errored(kErrorNoHeapMemory);
    1224             : 
    1225             :       X86RAData* raData = self->newRAData(1);
    1226           0 :       if (!raData) return DebugUtils::errored(kErrorNoHeapMemory);
    1227             : 
    1228             :       raData->tiedTotal = 1;
    1229             :       raData->tiedIndex.reset();
    1230             :       raData->tiedCount.reset();
    1231             :       raData->tiedCount.add(srcRegKind);
    1232             :       raData->inRegs.reset();
    1233             :       raData->outRegs.reset();
    1234             :       raData->clobberedRegs.reset();
    1235           0 :       raData->tiedArray[0].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
    1236             : 
    1237             :       sArg->setPassData(raData);
    1238           0 :       sArgData->sArg = sArg;
    1239             : 
    1240           0 :       cc->addBefore(sArg, call);
    1241             :     }
    1242             : 
    1243           0 :     sArg->_args |= Utils::mask(argIndex);
    1244             :     return kErrorOk;
    1245             :   }
    1246             : }
    1247             : 
    1248             : // ============================================================================
    1249             : // [asmjit::X86RAPass - Fetch]
    1250             : // ============================================================================
    1251             : 
    1252             : //! \internal
    1253             : //!
    1254             : //! Prepare the given function `func`.
    1255             : //!
    1256             : //! For each node:
    1257             : //! - Create and assign groupId and position.
    1258             : //! - Collect all variables and merge them to vaList.
    1259        1944 : Error X86RAPass::fetch() {
    1260             :   uint32_t archType = cc()->getArchType();
    1261             :   CCFunc* func = getFunc();
    1262             : 
    1263             :   CBNode* node_ = func;
    1264             :   CBNode* next = nullptr;
    1265             :   CBNode* stop = getStop();
    1266             : 
    1267      157464 :   TiedReg agTmp[80];
    1268             :   SArgData sArgList[80];
    1269             : 
    1270             :   uint32_t position = 0;
    1271             :   ZoneList<CBNode*>::Link* jLink = nullptr;
    1272             : 
    1273             :   // Global allocable registers.
    1274        1944 :   uint32_t* gaRegs = _gaRegs;
    1275             : 
    1276        1944 :   if (func->getFrameInfo().hasPreservedFP())
    1277           0 :     gaRegs[X86Reg::kKindGp] &= ~Utils::mask(X86Gp::kIdBp);
    1278             : 
    1279             :   // Allowed index registers (GP/XMM/YMM).
    1280        1944 :   const uint32_t indexMask = Utils::bits(_regCount.getGp()) & ~(Utils::mask(4));
    1281             : 
    1282             :   // --------------------------------------------------------------------------
    1283             :   // [VI Macros]
    1284             :   // --------------------------------------------------------------------------
    1285             : 
    1286             : #define RA_POPULATE(NODE) \
    1287             :   do { \
    1288             :     X86RAData* raData = newRAData(0); \
    1289             :     if (!raData) goto NoMem; \
    1290             :     NODE->setPassData(raData); \
    1291             :   } while (0)
    1292             : 
    1293             : #define RA_DECLARE() \
    1294             :   do { \
    1295             :     X86RegCount tiedCount; \
    1296             :     X86RegCount tiedIndex; \
    1297             :     uint32_t tiedTotal = 0; \
    1298             :     \
    1299             :     X86RegMask inRegs; \
    1300             :     X86RegMask outRegs; \
    1301             :     X86RegMask clobberedRegs; \
    1302             :     \
    1303             :     tiedCount.reset(); \
    1304             :     inRegs.reset(); \
    1305             :     outRegs.reset(); \
    1306             :     clobberedRegs.reset()
    1307             : 
    1308             : #define RA_FINALIZE(NODE) \
    1309             :     { \
    1310             :       X86RAData* raData = newRAData(tiedTotal); \
    1311             :       if (!raData) goto NoMem; \
    1312             :       \
    1313             :       tiedIndex.indexFromRegCount(tiedCount); \
    1314             :       raData->tiedCount = tiedCount; \
    1315             :       raData->tiedIndex = tiedIndex; \
    1316             :       \
    1317             :       raData->inRegs = inRegs; \
    1318             :       raData->outRegs = outRegs; \
    1319             :       raData->clobberedRegs = clobberedRegs; \
    1320             :       \
    1321             :       TiedReg* tied = agTmp; \
    1322             :       while (tiedTotal) { \
    1323             :         VirtReg* vreg = tied->vreg; \
    1324             :         \
    1325             :         uint32_t _kind  = vreg->getKind(); \
    1326             :         uint32_t _index = tiedIndex.get(_kind); \
    1327             :         \
    1328             :         tiedIndex.add(_kind); \
    1329             :         if (tied->inRegs) \
    1330             :           tied->allocableRegs = tied->inRegs; \
    1331             :         else if (tied->outPhysId != Globals::kInvalidRegId) \
    1332             :           tied->allocableRegs = Utils::mask(tied->outPhysId); \
    1333             :         else \
    1334             :           tied->allocableRegs &= ~inRegs.get(_kind); \
    1335             :         \
    1336             :         vreg->_tied = nullptr; \
    1337             :         raData->setTiedAt(_index, *tied); \
    1338             :         \
    1339             :         tied++; \
    1340             :         tiedTotal--; \
    1341             :       } \
    1342             :       NODE->setPassData(raData); \
    1343             :      } \
    1344             :   } while (0)
    1345             : 
    1346             : #define RA_INSERT(REG, TIED, FLAGS, NEW_ALLOCABLE) \
    1347             :   do { \
    1348             :     ASMJIT_ASSERT(REG->_tied == nullptr); \
    1349             :     TIED = &agTmp[tiedTotal++]; \
    1350             :     TIED->init(REG, FLAGS, 0, NEW_ALLOCABLE); \
    1351             :     TIED->refCount++; \
    1352             :     REG->_tied = TIED; \
    1353             :     \
    1354             :     if (assignRAId(REG) != kErrorOk) goto NoMem; \
    1355             :     tiedCount.add(REG->getKind()); \
    1356             :   } while (0)
    1357             : 
    1358             : #define RA_MERGE(REG, TIED, FLAGS, NEW_ALLOCABLE) \
    1359             :   do { \
    1360             :     TIED = REG->_tied; \
    1361             :     \
    1362             :     if (!TIED) { \
    1363             :       TIED = &agTmp[tiedTotal++]; \
    1364             :       TIED->init(REG, 0, 0, NEW_ALLOCABLE); \
    1365             :       REG->_tied = TIED; \
    1366             :       \
    1367             :       if (assignRAId(REG) != kErrorOk) goto NoMem; \
    1368             :       tiedCount.add(REG->getKind()); \
    1369             :     } \
    1370             :     \
    1371             :     TIED->flags |= FLAGS; \
    1372             :     TIED->refCount++; \
    1373             :   } while (0)
    1374             : 
    1375             :   // --------------------------------------------------------------------------
    1376             :   // [Loop]
    1377             :   // --------------------------------------------------------------------------
    1378             : 
    1379             :   do {
    1380       34686 : _Do:
    1381       36630 :     while (node_->hasPassData()) {
    1382           0 : _NextGroup:
    1383        1944 :       if (!jLink)
    1384             :         jLink = _jccList.getFirst();
    1385             :       else
    1386             :         jLink = jLink->getNext();
    1387             : 
    1388        1944 :       if (!jLink) goto _Done;
    1389             :       node_ = X86RAPass_getOppositeJccFlow(static_cast<CBJump*>(jLink->getValue()));
    1390             :     }
    1391             : 
    1392       36630 :     position++;
    1393             : 
    1394             :     next = node_->getNext();
    1395             :     node_->setPosition(position);
    1396             : 
    1397       36630 :     switch (node_->getType()) {
    1398             :       // ----------------------------------------------------------------------
    1399             :       // [Align/Embed]
    1400             :       // ----------------------------------------------------------------------
    1401             : 
    1402             :       case CBNode::kNodeAlign:
    1403             :       case CBNode::kNodeData:
    1404             :       default:
    1405           0 :         RA_POPULATE(node_);
    1406             :         break;
    1407             : 
    1408             :       // ----------------------------------------------------------------------
    1409             :       // [Hint]
    1410             :       // ----------------------------------------------------------------------
    1411             : 
    1412           0 :       case CBNode::kNodeHint: {
    1413             :         CCHint* node = static_cast<CCHint*>(node_);
    1414             :         RA_DECLARE();
    1415             : 
    1416           0 :         if (node->getHint() == CCHint::kHintAlloc) {
    1417             :           uint32_t remain[Globals::kMaxVRegKinds];
    1418             :           CCHint* cur = node;
    1419             : 
    1420           0 :           remain[X86Reg::kKindGp ] = _regCount.getGp() - 1 - func->getFrameInfo().hasPreservedFP();
    1421           0 :           remain[X86Reg::kKindMm ] = _regCount.getMm();
    1422           0 :           remain[X86Reg::kKindK  ] = _regCount.getK();
    1423           0 :           remain[X86Reg::kKindVec] = _regCount.getVec();
    1424             : 
    1425             :           // Merge as many alloc-hints as possible.
    1426             :           for (;;) {
    1427             :             VirtReg* vreg = static_cast<VirtReg*>(cur->getVReg());
    1428           0 :             TiedReg* tied = vreg->_tied;
    1429             : 
    1430             :             uint32_t kind = vreg->getKind();
    1431             :             uint32_t physId = cur->getValue();
    1432             :             uint32_t regMask = 0;
    1433             : 
    1434             :             // We handle both kInvalidReg and kInvalidValue.
    1435           0 :             if (physId < Globals::kInvalidRegId)
    1436             :               regMask = Utils::mask(physId);
    1437             : 
    1438           0 :             if (!tied) {
    1439           0 :               if (inRegs.has(kind, regMask) || remain[kind] == 0)
    1440             :                 break;
    1441           0 :               RA_INSERT(vreg, tied, TiedReg::kRReg, gaRegs[kind]);
    1442             : 
    1443           0 :               if (regMask != 0) {
    1444             :                 inRegs.xor_(kind, regMask);
    1445           0 :                 tied->inRegs = regMask;
    1446             :                 tied->setInPhysId(physId);
    1447             :               }
    1448           0 :               remain[kind]--;
    1449             :             }
    1450           0 :             else if (regMask != 0) {
    1451           0 :               if (inRegs.has(kind, regMask) && tied->inRegs != regMask)
    1452             :                 break;
    1453             : 
    1454           0 :               inRegs.xor_(kind, tied->inRegs | regMask);
    1455           0 :               tied->inRegs = regMask;
    1456             :               tied->setInPhysId(physId);
    1457             :             }
    1458             : 
    1459           0 :             if (cur != node)
    1460           0 :               cc()->removeNode(cur);
    1461             : 
    1462             :             cur = static_cast<CCHint*>(node->getNext());
    1463           0 :             if (!cur || cur->getType() != CBNode::kNodeHint || cur->getHint() != CCHint::kHintAlloc)
    1464             :               break;
    1465             :           }
    1466             : 
    1467             :           next = node->getNext();
    1468             :         }
    1469             :         else  {
    1470             :           VirtReg* vreg = static_cast<VirtReg*>(node->getVReg());
    1471             :           TiedReg* tied;
    1472             : 
    1473             :           uint32_t flags = 0;
    1474             :           switch (node->getHint()) {
    1475           0 :             case CCHint::kHintSpill       : flags = TiedReg::kRMem | TiedReg::kSpill; break;
    1476           0 :             case CCHint::kHintSave        : flags = TiedReg::kRMem                  ; break;
    1477           0 :             case CCHint::kHintSaveAndUnuse: flags = TiedReg::kRMem | TiedReg::kUnuse; break;
    1478           0 :             case CCHint::kHintUnuse       : flags = TiedReg::kUnuse                 ; break;
    1479             :           }
    1480           0 :           RA_INSERT(vreg, tied, flags, 0);
    1481             :         }
    1482             : 
    1483           0 :         RA_FINALIZE(node_);
    1484           0 :         break;
    1485             :       }
    1486             : 
    1487             :       // ----------------------------------------------------------------------
    1488             :       // [Label]
    1489             :       // ----------------------------------------------------------------------
    1490             : 
    1491             :       case CBNode::kNodeLabel: {
    1492           0 :         RA_POPULATE(node_);
    1493           0 :         if (node_ == func->getExitNode()) {
    1494           0 :           ASMJIT_PROPAGATE(addReturningNode(node_));
    1495           0 :           goto _NextGroup;
    1496             :         }
    1497             :         break;
    1498             :       }
    1499             : 
    1500             :       // ----------------------------------------------------------------------
    1501             :       // [Inst]
    1502             :       // ----------------------------------------------------------------------
    1503             : 
    1504       31106 :       case CBNode::kNodeInst: {
    1505             :         CBInst* node = static_cast<CBInst*>(node_);
    1506             : 
    1507             :         uint32_t instId = node->getInstId();
    1508             :         uint32_t flags = node->getFlags();
    1509             :         uint32_t options = node->getOptions();
    1510             :         uint32_t gpAllowedMask = 0xFFFFFFFF;
    1511             : 
    1512             :         Operand* opArray = node->getOpArray();
    1513             :         uint32_t opCount = node->getOpCount();
    1514             : 
    1515             :         RA_DECLARE();
    1516       31106 :         if (opCount) {
    1517             :           const X86Inst& inst = X86Inst::getInst(instId);
    1518             :           const X86Inst::CommonData& commonData = inst.getCommonData();
    1519             :           const X86SpecialInst* special = nullptr;
    1520             : 
    1521             :           // Collect instruction flags and merge all 'TiedReg's.
    1522       31106 :           if (commonData.isFpu())
    1523             :             flags |= CBNode::kFlagIsFp;
    1524             : 
    1525       31106 :           if (commonData.hasFixedRM() && (special = X86SpecialInst_get(instId, opArray, opCount)) != nullptr)
    1526           0 :             flags |= CBNode::kFlagIsSpecial;
    1527             : 
    1528       93438 :           for (uint32_t i = 0; i < opCount; i++) {
    1529       62332 :             Operand* op = &opArray[i];
    1530             :             VirtReg* vreg;
    1531             :             TiedReg* tied;
    1532             : 
    1533             :             if (op->isVirtReg()) {
    1534             :               vreg = cc()->getVirtRegById(op->getId());
    1535       48896 :               if (vreg->isFixed()) continue;
    1536             : 
    1537      119644 :               RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
    1538       48896 :               if (static_cast<X86Reg*>(op)->isGpb()) {
    1539           0 :                 tied->flags |= static_cast<X86Gp*>(op)->isGpbLo() ? TiedReg::kX86GpbLo : TiedReg::kX86GpbHi;
    1540           0 :                 if (archType == ArchInfo::kTypeX86) {
    1541             :                   // If a byte register is accessed in 32-bit mode we have to limit
    1542             :                   // all allocable registers for that variable to eax/ebx/ecx/edx.
    1543             :                   // Other variables are not affected.
    1544           0 :                   tied->allocableRegs &= 0x0F;
    1545             :                 }
    1546             :                 else {
    1547             :                   // It's fine if lo-byte register is accessed in 64-bit mode;
    1548             :                   // however, hi-byte has to be checked and if it's used all
    1549             :                   // registers (GP/XMM) could be only allocated in the lower eight
    1550             :                   // half. To do that, we patch 'allocableRegs' of all variables
    1551             :                   // we collected until now and change the allocable restriction
    1552             :                   // for variables that come after.
    1553           0 :                   if (static_cast<X86Gp*>(op)->isGpbHi()) {
    1554           0 :                     tied->allocableRegs &= 0x0F;
    1555           0 :                     if (gpAllowedMask != 0xFF) {
    1556           0 :                       for (uint32_t j = 0; j < i; j++)
    1557           0 :                         agTmp[j].allocableRegs &= (agTmp[j].flags & TiedReg::kX86GpbHi) ? 0x0F : 0xFF;
    1558             :                       gpAllowedMask = 0xFF;
    1559             :                     }
    1560             :                   }
    1561             :                 }
    1562             :               }
    1563             : 
    1564       48896 :               if (special) {
    1565           0 :                 uint32_t inReg = special[i].inReg;
    1566           0 :                 uint32_t outReg = special[i].outReg;
    1567             :                 uint32_t c;
    1568             : 
    1569           0 :                 if (static_cast<const X86Reg*>(op)->isGp())
    1570             :                   c = X86Reg::kKindGp;
    1571             :                 else
    1572             :                   c = X86Reg::kKindVec;
    1573             : 
    1574           0 :                 if (inReg != Globals::kInvalidRegId) {
    1575             :                   uint32_t mask = Utils::mask(inReg);
    1576             :                   inRegs.or_(c, mask);
    1577           0 :                   tied->inRegs |= mask;
    1578             :                 }
    1579             : 
    1580           0 :                 if (outReg != Globals::kInvalidRegId) {
    1581             :                   uint32_t mask = Utils::mask(outReg);
    1582             :                   outRegs.or_(c, mask);
    1583             :                   tied->setOutPhysId(outReg);
    1584             :                 }
    1585             : 
    1586           0 :                 tied->flags |= special[i].flags;
    1587             :               }
    1588             :               else {
    1589             :                 uint32_t inFlags = TiedReg::kRReg;
    1590             :                 uint32_t outFlags = TiedReg::kWReg;
    1591             :                 uint32_t combinedFlags;
    1592             : 
    1593       48896 :                 if (i == 0) {
    1594             :                   // Read/Write is usually the combination of the first operand.
    1595             :                   combinedFlags = inFlags | outFlags;
    1596             : 
    1597       30864 :                   if (node->getOptions() & CodeEmitter::kOptionOverwrite) {
    1598             :                     // Manually forcing write-only.
    1599             :                     combinedFlags = outFlags;
    1600             :                   }
    1601       30864 :                   else if (commonData.isUseW()) {
    1602             :                     // Write-only instruction.
    1603             :                     uint32_t movSize = commonData.getWriteSize();
    1604             :                     uint32_t regSize = vreg->getSize();
    1605             : 
    1606             :                     // Exception - If the source operand is a memory location
    1607             :                     // promote move size into 16 bytes.
    1608       21852 :                     if (opArray[1].isMem() && inst.getOperationData().isMovSsSd())
    1609             :                       movSize = 16;
    1610             : 
    1611       21852 :                     if (static_cast<const X86Reg*>(op)->isGp()) {
    1612             :                       uint32_t opSize = static_cast<const X86Reg*>(op)->getSize();
    1613             : 
    1614             :                       // Move size is zero in case that it should be determined
    1615             :                       // from the destination register.
    1616        7248 :                       if (movSize == 0)
    1617             :                         movSize = opSize;
    1618             : 
    1619             :                       // Handle the case that a 32-bit operation in 64-bit mode
    1620             :                       // always clears the rest of the destination register and
    1621             :                       // the case that move size is actually greater than or
    1622             :                       // equal to the size of the variable.
    1623        7248 :                       if (movSize >= 4 || movSize >= regSize)
    1624             :                         combinedFlags = outFlags;
    1625             :                     }
    1626       14604 :                     else if (movSize == 0 || movSize >= regSize) {
    1627             :                       // If move size is greater than or equal to the size of
    1628             :                       // the variable there is nothing to do, because the move
    1629             :                       // will overwrite the variable in all cases.
    1630             :                       combinedFlags = outFlags;
    1631             :                     }
    1632             :                   }
    1633        9012 :                   else if (commonData.isUseR()) {
    1634             :                     // Comparison/Test instructions don't modify any operand.
    1635             :                     combinedFlags = inFlags;
    1636             :                   }
    1637        9012 :                   else if (instId == X86Inst::kIdImul && opCount == 3) {
    1638             :                     // Imul.
    1639             :                     combinedFlags = outFlags;
    1640             :                   }
    1641             :                 }
    1642             :                 else {
    1643             :                   // Read-Only is usually the combination of the second/third/fourth operands.
    1644             :                   combinedFlags = inFlags;
    1645             : 
    1646             :                   // Idiv is a special instruction, never handled here.
    1647             :                   ASMJIT_ASSERT(instId != X86Inst::kIdIdiv);
    1648             : 
    1649             :                   // Xchg/Xadd/Imul.
    1650       18032 :                   if (commonData.isUseXX() || (instId == X86Inst::kIdImul && opCount == 3 && i == 1))
    1651             :                     combinedFlags = inFlags | outFlags;
    1652             :                 }
    1653       48896 :                 tied->flags |= combinedFlags;
    1654             :               }
    1655             :             }
    1656       13436 :             else if (op->isMem()) {
    1657             :               X86Mem* m = static_cast<X86Mem*>(op);
    1658             :               node->setMemOpIndex(i);
    1659             : 
    1660        6068 :               uint32_t specBase = special ? uint32_t(special[i].inReg) : uint32_t(Globals::kInvalidRegId);
    1661             : 
    1662        6068 :               if (m->hasBaseReg()) {
    1663             :                 uint32_t id = m->getBaseId();
    1664        6068 :                 if (cc()->isVirtRegValid(id)) {
    1665             :                   vreg = cc()->getVirtRegById(id);
    1666        6068 :                   if (!vreg->isStack() && !vreg->isFixed()) {
    1667       12136 :                     RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
    1668        6068 :                     if (m->isRegHome()) {
    1669             :                       uint32_t inFlags = TiedReg::kRMem;
    1670             :                       uint32_t outFlags = TiedReg::kWMem;
    1671             :                       uint32_t combinedFlags;
    1672             : 
    1673           0 :                       if (i == 0) {
    1674             :                         // Default for the first operand.
    1675             :                         combinedFlags = inFlags | outFlags;
    1676             : 
    1677           0 :                         if (commonData.isUseW()) {
    1678             :                           // Move to memory - setting the right flags is important
    1679             :                           // as if it's just move to the register. It's just a bit
    1680             :                           // simpler as there are no special cases.
    1681           0 :                           uint32_t movSize = std::max<uint32_t>(commonData.getWriteSize(), m->getSize());
    1682             :                           uint32_t regSize = vreg->getSize();
    1683             : 
    1684           0 :                           if (movSize >= regSize)
    1685             :                             combinedFlags = outFlags;
    1686             :                         }
    1687           0 :                         else if (commonData.isUseR()) {
    1688             :                           // Comparison/Test instructions don't modify any operand.
    1689             :                           combinedFlags = inFlags;
    1690             :                         }
    1691             :                       }
    1692             :                       else {
    1693             :                         // Default for the second operand.
    1694             :                         combinedFlags = inFlags;
    1695             : 
    1696             :                         // Handle Xchg instruction (modifies both operands).
    1697           0 :                         if (commonData.isUseXX())
    1698             :                           combinedFlags = inFlags | outFlags;
    1699             :                       }
    1700             : 
    1701           0 :                       tied->flags |= combinedFlags;
    1702             :                     }
    1703             :                     else {
    1704        6068 :                       if (specBase != Globals::kInvalidRegId) {
    1705             :                         uint32_t mask = Utils::mask(specBase);
    1706             :                         inRegs.or_(vreg->getKind(), mask);
    1707             :                         outRegs.or_(vreg->getKind(), mask);
    1708           0 :                         tied->inRegs |= mask;
    1709             :                         tied->setOutPhysId(specBase);
    1710           0 :                         tied->flags |= special[i].flags;
    1711             :                       }
    1712             :                       else {
    1713        6068 :                         tied->flags |= TiedReg::kRReg;
    1714             :                       }
    1715             :                     }
    1716             :                   }
    1717             :                 }
    1718             :               }
    1719             : 
    1720        6068 :               if (m->hasIndexReg()) {
    1721             :                 uint32_t id = m->getIndexId();
    1722           0 :                 if (cc()->isVirtRegValid(id)) {
    1723             :                   // Restrict allocation to all registers except ESP|RSP.
    1724             :                   vreg = cc()->getVirtRegById(m->getIndexId());
    1725           0 :                   if (!vreg->isFixed()) {
    1726             :                     // TODO: AVX vector operands support.
    1727           0 :                     RA_MERGE(vreg, tied, 0, gaRegs[X86Reg::kKindGp] & gpAllowedMask);
    1728           0 :                     tied->allocableRegs &= indexMask;
    1729           0 :                     tied->flags |= TiedReg::kRReg;
    1730             :                   }
    1731             :                 }
    1732             :               }
    1733             :             }
    1734             :           }
    1735             : 
    1736             :           node->setFlags(flags);
    1737       31106 :           if (tiedTotal) {
    1738             :             // Handle instructions which result in zeros/ones or nop if used with the
    1739             :             // same destination and source operand.
    1740       31358 :             if (tiedTotal == 1 && opCount >= 2 && opArray[0].isVirtReg() && opArray[1].isVirtReg() && !node->hasMemOp())
    1741         252 :               X86RAPass_prepareSingleVarInst(instId, &agTmp[0]);
    1742             :           }
    1743             : 
    1744             :           // Turn on AVX if the instruction operates on XMM|YMM|ZMM registers and uses VEX|EVEX prefix.
    1745       31106 :           if (tiedCount.getVec() && commonData.hasFlag(X86Inst::kFlagVex | X86Inst::kFlagEvex))
    1746           0 :             _avxEnabled = true;
    1747             :         }
    1748             : 
    1749             :         const RegOnly& extraReg = node->getExtraReg();
    1750       31106 :         if (extraReg.isValid()) {
    1751             :           uint32_t id = extraReg.getId();
    1752           0 :           if (cc()->isVirtRegValid(id)) {
    1753             :             VirtReg* vreg = cc()->getVirtRegById(id);
    1754             :             TiedReg* tied;
    1755           0 :             RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
    1756             : 
    1757           0 :             if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) {
    1758           0 :               tied->allocableRegs = Utils::mask(X86Gp::kIdCx);
    1759           0 :               tied->flags |= TiedReg::kXReg;
    1760             :             }
    1761             :             else {
    1762           0 :               tied->flags |= TiedReg::kRReg;
    1763             :             }
    1764             :           }
    1765             :         }
    1766             : 
    1767       85818 :         RA_FINALIZE(node_);
    1768             : 
    1769             :         // Handle conditional/unconditional jump.
    1770       31106 :         if (node->isJmpOrJcc()) {
    1771             :           CBJump* jNode = static_cast<CBJump*>(node);
    1772             :           CBLabel* jTarget = jNode->getTarget();
    1773             : 
    1774             :           // If this jump is unconditional we put next node to unreachable node
    1775             :           // list so we can eliminate possible dead code. We have to do this in
    1776             :           // all cases since we are unable to translate without fetch() step.
    1777             :           //
    1778             :           // We also advance our node pointer to the target node to simulate
    1779             :           // natural flow of the function.
    1780           0 :           if (jNode->isJmp()) {
    1781           0 :             if (next && !next->hasPassData())
    1782           0 :               ASMJIT_PROPAGATE(addUnreachableNode(next));
    1783             : 
    1784             :             // Jump not followed.
    1785           0 :             if (!jTarget) {
    1786           0 :               ASMJIT_PROPAGATE(addReturningNode(jNode));
    1787           0 :               goto _NextGroup;
    1788             :             }
    1789             : 
    1790             :             node_ = jTarget;
    1791           0 :             goto _Do;
    1792             :           }
    1793             :           else {
    1794             :             // Jump not followed.
    1795           0 :             if (!jTarget) break;
    1796             : 
    1797           0 :             if (jTarget->hasPassData()) {
    1798             :               uint32_t jTargetPosition = jTarget->getPosition();
    1799             : 
    1800             :               // Update CBNode::kFlagIsTaken to true if this is a conditional
    1801             :               // backward jump. This behavior can be overridden by using
    1802             :               // `X86Inst::kOptionTaken` when the instruction is created.
    1803           0 :               if (!jNode->isTaken() && opCount == 1 && jTargetPosition <= position) {
    1804           0 :                 jNode->_flags |= CBNode::kFlagIsTaken;
    1805             :               }
    1806             :             }
    1807           0 :             else if (next->hasPassData()) {
    1808             :               node_ = jTarget;
    1809           0 :               goto _Do;
    1810             :             }
    1811             :             else {
    1812           0 :               ASMJIT_PROPAGATE(addJccNode(jNode));
    1813             :               node_ = X86RAPass_getJccFlow(jNode);
    1814           0 :               goto _Do;
    1815             :             }
    1816             :           }
    1817             :         }
    1818             :         break;
    1819             :       }
    1820             : 
    1821             :       // ----------------------------------------------------------------------
    1822             :       // [Func-Entry]
    1823             :       // ----------------------------------------------------------------------
    1824             : 
    1825        1944 :       case CBNode::kNodeFunc: {
    1826             :         ASMJIT_ASSERT(node_ == func);
    1827        1944 :         X86RAPass_assignStackArgsRegId(this, func);
    1828             : 
    1829             :         FuncDetail& fd = func->getDetail();
    1830             :         TiedReg* tied;
    1831             : 
    1832             :         RA_DECLARE();
    1833        1944 :         cc()->setCursor(node_);
    1834             : 
    1835             :         X86Gp saReg;
    1836             :         uint32_t argCount = fd.getArgCount();
    1837             : 
    1838        1944 :         for (uint32_t i = 0; i < argCount; i++) {
    1839           0 :           const FuncDetail::Value& arg = fd.getArg(i);
    1840             : 
    1841             :           VirtReg* vReg = func->getArg(i);
    1842           0 :           if (!vReg) continue;
    1843             : 
    1844             :           // Overlapped function arguments.
    1845           0 :           if (vReg->_tied)
    1846           0 :             return DebugUtils::errored(kErrorOverlappedRegs);
    1847             : 
    1848             :           uint32_t aKind = X86Reg::kindOf(arg.getRegType());
    1849             :           uint32_t vKind = vReg->getKind();
    1850             : 
    1851           0 :           if (arg.byReg()) {
    1852           0 :             if (aKind == vKind) {
    1853           0 :               RA_INSERT(vReg, tied, TiedReg::kWReg, 0);
    1854             :               tied->setOutPhysId(arg.getRegId());
    1855             :             }
    1856             :             else {
    1857           0 :               X86Reg rTmp = cc()->newReg(arg.getTypeId(), "arg%u", i);
    1858             :               VirtReg* vTmp = cc()->getVirtReg(rTmp);
    1859             : 
    1860           0 :               RA_INSERT(vTmp, tied, TiedReg::kWReg, 0);
    1861             :               tied->setOutPhysId(arg.getRegId());
    1862             : 
    1863             :               X86Reg dstReg(X86Reg::fromSignature(vReg->getSignature(), vReg->getId()));
    1864             :               X86Reg srcReg(X86Reg::fromSignature(vTmp->getSignature(), vTmp->getId()));
    1865             : 
    1866             :               // Emit conversion after the prolog.
    1867           0 :               return X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(cc()),
    1868             :                 dstReg, vReg->getTypeId(),
    1869           0 :                 srcReg, vTmp->getTypeId(), _avxEnabled);
    1870             :             }
    1871             :           }
    1872             :           else {
    1873             :             // Instead of complicating the prolog allocation we create a virtual
    1874             :             // register that holds the base address to all arguments passed by
    1875             :             // stack and then insert nodes that copy these arguments to registers.
    1876           0 :             if (!saReg.isValid()) {
    1877           0 :               saReg = cc()->newGpz("__args");
    1878           0 :               if (!saReg.isValid()) goto NoMem;
    1879             : 
    1880             :               VirtReg* saBase = cc()->getVirtReg(saReg);
    1881           0 :               RA_INSERT(saBase, tied, TiedReg::kWReg, 0);
    1882             : 
    1883           0 :               if (func->getFrameInfo().hasPreservedFP())
    1884           0 :                 saBase->_isFixed = true;
    1885             :               tied->setOutPhysId(func->getFrameInfo().getStackArgsRegId());
    1886             :             }
    1887             : 
    1888             :             // Argument passed by stack is handled after the prolog.
    1889             :             X86Gp aReg = X86Gp::fromSignature(vReg->getSignature(), vReg->getId());
    1890             :             X86Mem aMem = x86::ptr(saReg, arg.getStackOffset());
    1891             :             aMem.setArgHome();
    1892             : 
    1893           0 :             ASMJIT_PROPAGATE(
    1894             :               X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(cc()),
    1895             :                 aReg, vReg->getTypeId(), aMem, arg.getTypeId(), _avxEnabled));
    1896             :           }
    1897             :         }
    1898             : 
    1899             :         // If saReg is not needed, clear it also from FuncFrameInfo.
    1900        1944 :         if (!saReg.isValid())
    1901             :           func->getFrameInfo().setStackArgsRegId(Globals::kInvalidRegId);
    1902             : 
    1903        1944 :         RA_FINALIZE(node_);
    1904             :         next = node_->getNext();
    1905        1944 :         break;
    1906             :       }
    1907             : 
    1908             :       // ----------------------------------------------------------------------
    1909             :       // [End]
    1910             :       // ----------------------------------------------------------------------
    1911             : 
    1912             :       case CBNode::kNodeSentinel: {
    1913           0 :         RA_POPULATE(node_);
    1914           0 :         ASMJIT_PROPAGATE(addReturningNode(node_));
    1915           0 :         goto _NextGroup;
    1916             :       }
    1917             : 
    1918             :       // ----------------------------------------------------------------------
    1919             :       // [Func-Exit]
    1920             :       // ----------------------------------------------------------------------
    1921             : 
    1922        1944 :       case CBNode::kNodeFuncExit: {
    1923             :         CCFuncRet* node = static_cast<CCFuncRet*>(node_);
    1924        1944 :         ASMJIT_PROPAGATE(addReturningNode(node));
    1925             : 
    1926             :         FuncDetail& fd = func->getDetail();
    1927             :         RA_DECLARE();
    1928             : 
    1929        1944 :         if (fd.hasRet()) {
    1930             :           const FuncDetail::Value& ret = fd.getRet(0);
    1931             :           uint32_t retKind = X86Reg::kindOf(ret.getRegType());
    1932             : 
    1933        5832 :           for (uint32_t i = 0; i < 2; i++) {
    1934             :             Operand_* op = &node->_ret[i];
    1935             :             if (op->isVirtReg()) {
    1936             :               VirtReg* vreg = cc()->getVirtRegById(op->getId());
    1937             :               TiedReg* tied;
    1938        3888 :               RA_MERGE(vreg, tied, 0, 0);
    1939             : 
    1940        1944 :               if (retKind == vreg->getKind()) {
    1941        1944 :                 tied->flags |= TiedReg::kRReg;
    1942        1944 :                 tied->inRegs = Utils::mask(ret.getRegId());
    1943             :                 inRegs.or_(retKind, tied->inRegs);
    1944             :               }
    1945           0 :               else if (retKind == X86Reg::kKindFp) {
    1946           0 :                 uint32_t fldFlag = ret.getTypeId() == TypeId::kF32 ? TiedReg::kX86Fld4 : TiedReg::kX86Fld8;
    1947           0 :                 tied->flags |= TiedReg::kRMem | fldFlag;
    1948             :               }
    1949             :               else {
    1950             :                 // TODO: Fix possible other return type conversions.
    1951           0 :                 ASMJIT_NOT_REACHED();
    1952             :               }
    1953             :             }
    1954             :           }
    1955             :         }
    1956        3888 :         RA_FINALIZE(node_);
    1957             : 
    1958        1944 :         if (!next->hasPassData())
    1959        1944 :           ASMJIT_PROPAGATE(addUnreachableNode(next));
    1960        1944 :         goto _NextGroup;
    1961             :       }
    1962             : 
    1963             :       // ----------------------------------------------------------------------
    1964             :       // [Func-Call]
    1965             :       // ----------------------------------------------------------------------
    1966             : 
    1967        1636 :       case CBNode::kNodeFuncCall: {
    1968             :         CCFuncCall* node = static_cast<CCFuncCall*>(node_);
    1969             :         FuncDetail& fd = node->getDetail();
    1970             : 
    1971        1636 :         Operand_* target = node->_opArray;
    1972        1636 :         Operand_* args = node->_args;
    1973        1636 :         Operand_* rets = node->_ret;
    1974             : 
    1975             :         func->getFrameInfo().enableCalls();
    1976        1636 :         func->getFrameInfo().mergeCallFrameSize(fd.getArgStackSize());
    1977             :         // TODO: Each function frame should also define its stack arguments' alignment.
    1978             :         // func->getFrameInfo().mergeCallFrameAlignment();
    1979             : 
    1980             :         uint32_t i;
    1981             :         uint32_t argCount = fd.getArgCount();
    1982             :         uint32_t sArgCount = 0;
    1983        1636 :         uint32_t gpAllocableMask = gaRegs[X86Reg::kKindGp] & ~node->getDetail().getUsedRegs(X86Reg::kKindGp);
    1984             : 
    1985             :         VirtReg* vreg;
    1986             :         TiedReg* tied;
    1987             : 
    1988             :         RA_DECLARE();
    1989             : 
    1990             :         // Function-call operand.
    1991             :         if (target->isVirtReg()) {
    1992             :           vreg = cc()->getVirtRegById(target->getId());
    1993        1636 :           RA_MERGE(vreg, tied, 0, 0);
    1994             : 
    1995        1636 :           tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
    1996        1636 :           if (tied->inRegs == 0)
    1997        1636 :             tied->allocableRegs |= gpAllocableMask;
    1998             :         }
    1999           0 :         else if (target->isMem()) {
    2000             :           X86Mem* m = static_cast<X86Mem*>(target);
    2001             : 
    2002           0 :           if (m->hasBaseReg() &&  Operand::isPackedId(m->getBaseId())) {
    2003             :             vreg = cc()->getVirtRegById(m->getBaseId());
    2004           0 :             if (!vreg->isStack()) {
    2005           0 :               RA_MERGE(vreg, tied, 0, 0);
    2006           0 :               if (m->isRegHome()) {
    2007           0 :                 tied->flags |= TiedReg::kRMem | TiedReg::kRCall;
    2008             :               }
    2009             :               else {
    2010           0 :                 tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
    2011           0 :                 if (tied->inRegs == 0)
    2012           0 :                   tied->allocableRegs |= gpAllocableMask;
    2013             :               }
    2014             :             }
    2015             :           }
    2016             : 
    2017           0 :           if (m->hasIndexReg() && Operand::isPackedId(m->getIndexId())) {
    2018             :             // Restrict allocation to all registers except ESP/RSP.
    2019             :             vreg = cc()->getVirtRegById(m->getIndexId());
    2020           0 :             RA_MERGE(vreg, tied, 0, 0);
    2021             : 
    2022           0 :             tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
    2023           0 :             if ((tied->inRegs & ~indexMask) == 0)
    2024           0 :               tied->allocableRegs &= gpAllocableMask & indexMask;
    2025             :           }
    2026             :         }
    2027             : 
    2028             :         // Function-call arguments.
    2029        3486 :         for (i = 0; i < argCount; i++) {
    2030        1850 :           Operand_* op = &args[i];
    2031         404 :           if (!op->isVirtReg()) continue;
    2032             : 
    2033             :           vreg = cc()->getVirtRegById(op->getId());
    2034             :           const FuncDetail::Value& arg = fd.getArg(i);
    2035             : 
    2036        1446 :           if (arg.byReg()) {
    2037        2892 :             RA_MERGE(vreg, tied, 0, 0);
    2038             : 
    2039             :             uint32_t argClass = X86Reg::kindOf(arg.getRegType());
    2040             : 
    2041        1446 :             if (vreg->getKind() == argClass) {
    2042        1446 :               tied->inRegs |= Utils::mask(arg.getRegId());
    2043        1446 :               tied->flags |= TiedReg::kRReg | TiedReg::kRFunc;
    2044             :             }
    2045             :             else {
    2046             :               // TODO: Function-call argument conversion.
    2047             :             }
    2048             :           }
    2049             :           // If this is a stack-based argument we insert CCPushArg instead of
    2050             :           // using TiedReg. It improves the code, because the argument can be
    2051             :           // moved onto stack as soon as it is ready and the register used by
    2052             :           // the variable can be reused for something else. It is also much
    2053             :           // easier to handle argument conversions, because there will be at
    2054             :           // most only one node per conversion.
    2055             :           else {
    2056           0 :             if (X86RAPass_insertPushArg(this, node, vreg, gaRegs, arg, i, sArgList, sArgCount) != kErrorOk)
    2057           0 :               goto NoMem;
    2058             :           }
    2059             :         }
    2060             : 
    2061             :         // Function-call returns.
    2062        4908 :         for (i = 0; i < 2; i++) {
    2063        3272 :           Operand_* op = &rets[i];
    2064        1636 :           if (!op->isVirtReg()) continue;
    2065             : 
    2066             :           const FuncDetail::Value& ret = fd.getRet(i);
    2067        1636 :           if (ret.byReg()) {
    2068             :             uint32_t retKind = X86Reg::kindOf(ret.getRegType());
    2069             : 
    2070             :             vreg = cc()->getVirtRegById(op->getId());
    2071        4908 :             RA_MERGE(vreg, tied, 0, 0);
    2072             : 
    2073        1636 :             if (vreg->getKind() == retKind) {
    2074             :               tied->setOutPhysId(ret.getRegId());
    2075        1636 :               tied->flags |= TiedReg::kWReg | TiedReg::kWFunc;
    2076             :             }
    2077             :             else {
    2078             :               // TODO: Function-call return value conversion.
    2079             :             }
    2080             :           }
    2081             :         }
    2082             : 
    2083             :         // Init clobbered.
    2084        1636 :         clobberedRegs.set(X86Reg::kKindGp , Utils::bits(_regCount.getGp())  & (fd.getPassedRegs(X86Reg::kKindGp ) | ~fd.getPreservedRegs(X86Reg::kKindGp )));
    2085        1636 :         clobberedRegs.set(X86Reg::kKindMm , Utils::bits(_regCount.getMm())  & (fd.getPassedRegs(X86Reg::kKindMm ) | ~fd.getPreservedRegs(X86Reg::kKindMm )));
    2086        1636 :         clobberedRegs.set(X86Reg::kKindK  , Utils::bits(_regCount.getK())   & (fd.getPassedRegs(X86Reg::kKindK  ) | ~fd.getPreservedRegs(X86Reg::kKindK  )));
    2087        1636 :         clobberedRegs.set(X86Reg::kKindVec, Utils::bits(_regCount.getVec()) & (fd.getPassedRegs(X86Reg::kKindVec) | ~fd.getPreservedRegs(X86Reg::kKindVec)));
    2088             : 
    2089        6354 :         RA_FINALIZE(node_);
    2090             :         break;
    2091             :       }
    2092             :     }
    2093             : 
    2094             :     node_ = next;
    2095       34686 :   } while (node_ != stop);
    2096             : 
    2097        1944 : _Done:
    2098             :   // Mark exit label and end node as fetched, otherwise they can be removed by
    2099             :   // `removeUnreachableCode()`, which could lead to a crash in some later step.
    2100             :   node_ = func->getEnd();
    2101        1944 :   if (!node_->hasPassData()) {
    2102             :     CBLabel* fExit = func->getExitNode();
    2103        1944 :     RA_POPULATE(fExit);
    2104        1944 :     fExit->setPosition(++position);
    2105             : 
    2106        1944 :     RA_POPULATE(node_);
    2107        1944 :     node_->setPosition(++position);
    2108             :   }
    2109             :   return kErrorOk;
    2110             : 
    2111             :   // --------------------------------------------------------------------------
    2112             :   // [Failure]
    2113             :   // --------------------------------------------------------------------------
    2114             : 
    2115             : NoMem:
    2116             :   return DebugUtils::errored(kErrorNoHeapMemory);
    2117             : }
    2118             : 
    2119             : // ============================================================================
    2120             : // [asmjit::X86RAPass - Annotate]
    2121             : // ============================================================================
    2122             : 
    2123           0 : Error X86RAPass::annotate() {
    2124             : #if !defined(ASMJIT_DISABLE_LOGGING)
    2125             :   CCFunc* func = getFunc();
    2126             : 
    2127             :   CBNode* node_ = func;
    2128             :   CBNode* end = func->getEnd();
    2129             : 
    2130           0 :   Zone& dataZone = cc()->_cbDataZone;
    2131             :   StringBuilderTmp<256> sb;
    2132             : 
    2133           0 :   uint32_t maxLen = 0;
    2134           0 :   while (node_ && node_ != end) {
    2135           0 :     if (!node_->hasInlineComment()) {
    2136           0 :       if (node_->getType() == CBNode::kNodeInst) {
    2137             :         CBInst* node = static_cast<CBInst*>(node_);
    2138           0 :         Logging::formatInstruction(
    2139             :           sb,
    2140             :           0,
    2141             :           cc(),
    2142             :           cc()->getArchType(),
    2143             :           node->getInstDetail(), node->getOpArray(), node->getOpCount());
    2144             : 
    2145             :         node_->setInlineComment(
    2146           0 :           static_cast<char*>(dataZone.dup(sb.getData(), sb.getLength(), true)));
    2147           0 :         maxLen = std::max<uint32_t>(maxLen, static_cast<uint32_t>(sb.getLength()));
    2148             : 
    2149           0 :         sb.clear();
    2150             :       }
    2151             :     }
    2152             : 
    2153             :     node_ = node_->getNext();
    2154             :   }
    2155           0 :   _annotationLength = maxLen + 1;
    2156             : #endif // !ASMJIT_DISABLE_LOGGING
    2157             : 
    2158           0 :   return kErrorOk;
    2159             : }
    2160             : 
    2161             : // ============================================================================
    2162             : // [asmjit::X86BaseAlloc]
    2163             : // ============================================================================
    2164             : 
    2165             : struct X86BaseAlloc {
    2166             :   // --------------------------------------------------------------------------
    2167             :   // [Construction / Destruction]
    2168             :   // --------------------------------------------------------------------------
    2169             : 
    2170        1944 :   ASMJIT_INLINE X86BaseAlloc(X86RAPass* context) {
    2171        1944 :     _context = context;
    2172        1944 :     _cc = context->cc();
    2173             :   }
    2174             :   ASMJIT_INLINE ~X86BaseAlloc() {}
    2175             : 
    2176             :   // --------------------------------------------------------------------------
    2177             :   // [Accessors]
    2178             :   // --------------------------------------------------------------------------
    2179             : 
    2180             :   //! Get the context.
    2181             :   ASMJIT_INLINE X86RAPass* getContext() const { return _context; }
    2182             :   //! Get the current state (always the same instance as X86RAPass::_x86State).
    2183       10360 :   ASMJIT_INLINE X86RAState* getState() const { return _context->getState(); }
    2184             : 
    2185             :   //! Get the node.
    2186             :   ASMJIT_INLINE CBNode* getNode() const { return _node; }
    2187             : 
    2188             :   //! Get TiedReg list (all).
    2189             :   ASMJIT_INLINE TiedReg* getTiedArray() const { return _tiedArray[0]; }
    2190             :   //! Get TiedReg list (per class).
    2191      333328 :   ASMJIT_INLINE TiedReg* getTiedArrayByKind(uint32_t kind) const { return _tiedArray[kind]; }
    2192             : 
    2193             :   //! Get TiedReg count (all).
    2194             :   ASMJIT_INLINE uint32_t getTiedCount() const { return _tiedTotal; }
    2195             :   //! Get TiedReg count (per class).
    2196             :   ASMJIT_INLINE uint32_t getTiedCountByKind(uint32_t kind) const { return _tiedCount.get(kind); }
    2197             : 
    2198             :   //! Get if all variables of the given register `kind` are done.
    2199             :   ASMJIT_INLINE bool isTiedDone(uint32_t kind) const { return _tiedDone.get(kind) == _tiedCount.get(kind); }
    2200             : 
    2201             :   //! Get how many variables have been allocated.
    2202             :   ASMJIT_INLINE uint32_t getTiedDone(uint32_t kind) const { return _tiedDone.get(kind); }
    2203             :   //! Add to the count of variables allocated.
    2204       26014 :   ASMJIT_INLINE void addTiedDone(uint32_t kind, uint32_t n = 1) { _tiedDone.add(kind, n); }
    2205             : 
    2206             :   //! Get number of allocable registers per class.
    2207             :   ASMJIT_INLINE uint32_t getGaRegs(uint32_t kind) const {
    2208             :     return _context->_gaRegs[kind];
    2209             :   }
    2210             : 
    2211             :   // --------------------------------------------------------------------------
    2212             :   // [Init / Cleanup]
    2213             :   // --------------------------------------------------------------------------
    2214             : 
    2215             : protected:
    2216             :   // Just to prevent calling these methods by X86RAPass::translate().
    2217             :   ASMJIT_INLINE void init(CBNode* node, X86RAData* map);
    2218             :   ASMJIT_INLINE void cleanup();
    2219             : 
    2220             :   // --------------------------------------------------------------------------
    2221             :   // [Unuse]
    2222             :   // --------------------------------------------------------------------------
    2223             : 
    2224             :   template<int C>
    2225             :   ASMJIT_INLINE void unuseBefore();
    2226             : 
    2227             :   template<int C>
    2228             :   ASMJIT_INLINE void unuseAfter();
    2229             : 
    2230             :   // --------------------------------------------------------------------------
    2231             :   // [Members]
    2232             :   // --------------------------------------------------------------------------
    2233             : 
    2234             :   //! RA context.
    2235             :   X86RAPass* _context;
    2236             :   //! Compiler.
    2237             :   X86Compiler* _cc;
    2238             : 
    2239             :   //! Node.
    2240             :   CBNode* _node;
    2241             : 
    2242             :   //! Register allocator (RA) data.
    2243             :   X86RAData* _raData;
    2244             :   //! TiedReg list (per register kind).
    2245             :   TiedReg* _tiedArray[Globals::kMaxVRegKinds];
    2246             : 
    2247             :   //! Count of all TiedReg's.
    2248             :   uint32_t _tiedTotal;
    2249             : 
    2250             :   //! TiedReg's total counter.
    2251             :   X86RegCount _tiedCount;
    2252             :   //! TiedReg's done counter.
    2253             :   X86RegCount _tiedDone;
    2254             : };
    2255             : 
    2256             : // ============================================================================
    2257             : // [asmjit::X86BaseAlloc - Init / Cleanup]
    2258             : // ============================================================================
    2259             : 
    2260             : ASMJIT_INLINE void X86BaseAlloc::init(CBNode* node, X86RAData* raData) {
    2261       36630 :   _node = node;
    2262       36630 :   _raData = raData;
    2263             : 
    2264             :   // We have to set the correct cursor in case any instruction is emitted
    2265             :   // during the allocation phase; it has to be emitted before the current
    2266             :   // instruction.
    2267       36630 :   _cc->_setCursor(node->getPrev());
    2268             : 
    2269             :   // Setup the lists of variables.
    2270             :   {
    2271             :     TiedReg* tied = raData->getTiedArray();
    2272       36630 :     _tiedArray[X86Reg::kKindGp ] = tied;
    2273       36630 :     _tiedArray[X86Reg::kKindMm ] = tied + raData->getTiedStart(X86Reg::kKindMm );
    2274       36630 :     _tiedArray[X86Reg::kKindK  ] = tied + raData->getTiedStart(X86Reg::kKindK  );
    2275       36630 :     _tiedArray[X86Reg::kKindVec] = tied + raData->getTiedStart(X86Reg::kKindVec);
    2276             :   }
    2277             : 
    2278             :   // Setup counters.
    2279       36630 :   _tiedTotal = raData->tiedTotal;
    2280       36630 :   _tiedCount = raData->tiedCount;
    2281             :   _tiedDone.reset();
    2282             : 
    2283             :   // Connect VREG->TIED.
    2284       98004 :   for (uint32_t i = 0; i < _tiedTotal; i++) {
    2285       61374 :     TiedReg* tied = &_tiedArray[0][i];
    2286       61374 :     VirtReg* vreg = tied->vreg;
    2287       61374 :     vreg->_tied = tied;
    2288             :   }
    2289             : }
    2290             : 
    2291             : ASMJIT_INLINE void X86BaseAlloc::cleanup() {
    2292             :   // Disconnect VREG->TIED.
    2293       96060 :   for (uint32_t i = 0; i < _tiedTotal; i++) {
    2294       61374 :     TiedReg* tied = &_tiedArray[0][i];
    2295       61374 :     VirtReg* vreg = tied->vreg;
    2296       61374 :     vreg->_tied = nullptr;
    2297             :   }
    2298             : }
    2299             : 
    2300             : // ============================================================================
    2301             : // [asmjit::X86BaseAlloc - Unuse]
    2302             : // ============================================================================
    2303             : 
    2304             : template<int C>
    2305             : ASMJIT_INLINE void X86BaseAlloc::unuseBefore() {
    2306             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    2307             :   uint32_t tiedCount = getTiedCountByKind(C);
    2308             : 
    2309             :   const uint32_t checkFlags = TiedReg::kXReg  |
    2310             :                               TiedReg::kRMem  |
    2311             :                               TiedReg::kRFunc |
    2312             :                               TiedReg::kRCall ;
    2313             : 
    2314       89706 :   for (uint32_t i = 0; i < tiedCount; i++) {
    2315       56656 :     TiedReg* tied = &tiedArray[i];
    2316       56656 :     if ((tied->flags & checkFlags) == TiedReg::kWReg)
    2317       22104 :       _context->unuse<C>(tied->vreg);
    2318             :   }
    2319             : }
    2320             : 
    2321             : template<int C>
    2322             : ASMJIT_INLINE void X86BaseAlloc::unuseAfter() {
    2323             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    2324             :   uint32_t tiedCount = getTiedCountByKind(C);
    2325             : 
    2326       96060 :   for (uint32_t i = 0; i < tiedCount; i++) {
    2327       61374 :     TiedReg* tied = &tiedArray[i];
    2328       61374 :     if (tied->flags & TiedReg::kUnuse)
    2329       21796 :       _context->unuse<C>(tied->vreg);
    2330             :   }
    2331             : }
    2332             : 
    2333             : // ============================================================================
    2334             : // [asmjit::X86VarAlloc]
    2335             : // ============================================================================
    2336             : 
    2337             : //! \internal
    2338             : //!
    2339             : //! Register allocator context (asm instructions).
    2340             : struct X86VarAlloc : public X86BaseAlloc {
    2341             :   // --------------------------------------------------------------------------
    2342             :   // [Construction / Destruction]
    2343             :   // --------------------------------------------------------------------------
    2344             : 
    2345        1944 :   ASMJIT_INLINE X86VarAlloc(X86RAPass* context) : X86BaseAlloc(context) {}
    2346        1944 :   ASMJIT_INLINE ~X86VarAlloc() {}
    2347             : 
    2348             :   // --------------------------------------------------------------------------
    2349             :   // [Run]
    2350             :   // --------------------------------------------------------------------------
    2351             : 
    2352             :   Error run(CBNode* node);
    2353             : 
    2354             :   // --------------------------------------------------------------------------
    2355             :   // [Init / Cleanup]
    2356             :   // --------------------------------------------------------------------------
    2357             : 
    2358             : protected:
    2359             :   // Just to prevent calling these methods by X86RAPass::translate().
    2360             :   ASMJIT_INLINE void init(CBNode* node, X86RAData* map);
    2361             :   ASMJIT_INLINE void cleanup();
    2362             : 
    2363             :   // --------------------------------------------------------------------------
    2364             :   // [Plan / Spill / Alloc]
    2365             :   // --------------------------------------------------------------------------
    2366             : 
    2367             :   template<int C>
    2368             :   ASMJIT_INLINE void plan();
    2369             : 
    2370             :   template<int C>
    2371             :   ASMJIT_INLINE void spill();
    2372             : 
    2373             :   template<int C>
    2374             :   ASMJIT_INLINE void alloc();
    2375             : 
    2376             :   // --------------------------------------------------------------------------
    2377             :   // [GuessAlloc / GuessSpill]
    2378             :   // --------------------------------------------------------------------------
    2379             : 
    2380             :   //! Guess which register is the best candidate for `vreg` from `allocableRegs`.
    2381             :   //!
    2382             :   //! The guess is based on looking ahead and inspecting register allocator
    2383             :   //! instructions. The main reason is to prevent allocation to a register
    2384             :   //! which is needed by next instruction(s). The guess look tries to go as far
    2385             :   //! as possible, after the remaining registers are zero, the mask of previous
    2386             :   //! registers (called 'safeRegs') is returned.
    2387             :   template<int C>
    2388             :   ASMJIT_INLINE uint32_t guessAlloc(VirtReg* vreg, uint32_t allocableRegs);
    2389             : 
    2390             :   //! Guess whether to move the given `vreg` instead of spill.
    2391             :   template<int C>
    2392             :   ASMJIT_INLINE uint32_t guessSpill(VirtReg* vreg, uint32_t allocableRegs);
    2393             : 
    2394             :   // --------------------------------------------------------------------------
    2395             :   // [Modified]
    2396             :   // --------------------------------------------------------------------------
    2397             : 
    2398             :   template<int C>
    2399             :   ASMJIT_INLINE void modified();
    2400             : 
    2401             :   // --------------------------------------------------------------------------
    2402             :   // [Members]
    2403             :   // --------------------------------------------------------------------------
    2404             : 
    2405             :   //! Will alloc to these registers.
    2406             :   X86RegMask _willAlloc;
    2407             :   //! Will spill these registers.
    2408             :   X86RegMask _willSpill;
    2409             : };
    2410             : 
    2411             : // ============================================================================
    2412             : // [asmjit::X86VarAlloc - Run]
    2413             : // ============================================================================
    2414             : 
    2415       34994 : Error X86VarAlloc::run(CBNode* node_) {
    2416             :   // Initialize.
    2417             :   X86RAData* raData = node_->getPassData<X86RAData>();
    2418             :   // Initialize the allocator; connect Vd->Va.
    2419             :   init(node_, raData);
    2420             : 
    2421       34994 :   if (raData->tiedTotal != 0) {
    2422             :     // Unuse overwritten variables.
    2423             :     unuseBefore<X86Reg::kKindGp>();
    2424             :     unuseBefore<X86Reg::kKindMm>();
    2425             :     unuseBefore<X86Reg::kKindVec>();
    2426             : 
    2427             :     // Plan the allocation. Planner assigns input/output registers for each
    2428             :     // variable and decides whether to allocate it in register or stack.
    2429             :     plan<X86Reg::kKindGp>();
    2430             :     plan<X86Reg::kKindMm>();
    2431             :     plan<X86Reg::kKindVec>();
    2432             : 
    2433             :     // Spill all variables marked by plan().
    2434             :     spill<X86Reg::kKindGp>();
    2435             :     spill<X86Reg::kKindMm>();
    2436             :     spill<X86Reg::kKindVec>();
    2437             : 
    2438             :     // Alloc all variables marked by plan().
    2439             :     alloc<X86Reg::kKindGp>();
    2440             :     alloc<X86Reg::kKindMm>();
    2441             :     alloc<X86Reg::kKindVec>();
    2442             : 
    2443             :     // Translate node operands.
    2444       33050 :     if (node_->getType() == CBNode::kNodeInst) {
    2445             :       CBInst* node = static_cast<CBInst*>(node_);
    2446       31106 :       if (node->hasExtraReg()) {
    2447             :         Reg reg = node->getExtraReg().toReg<Reg>();
    2448           0 :         ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, &reg, 1));
    2449             :         node->setExtraReg(reg);
    2450             :       }
    2451       31106 :       ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount()));
    2452             :     }
    2453        1944 :     else if (node_->getType() == CBNode::kNodePushArg) {
    2454             :       CCPushArg* node = static_cast<CCPushArg*>(node_);
    2455             : 
    2456             :       CCFuncCall* call = static_cast<CCFuncCall*>(node->getCall());
    2457             :       FuncDetail& fd = call->getDetail();
    2458             : 
    2459             :       uint32_t argIndex = 0;
    2460           0 :       uint32_t argMask = node->_args;
    2461             : 
    2462             :       VirtReg* cvtReg = node->getCvtReg();
    2463             :       VirtReg* srcReg = node->getSrcReg();
    2464             : 
    2465             :       // Convert first.
    2466             :       ASMJIT_ASSERT(srcReg->getPhysId() != Globals::kInvalidRegId);
    2467             : 
    2468           0 :       if (cvtReg) {
    2469             :         ASMJIT_ASSERT(cvtReg->getPhysId() != Globals::kInvalidRegId);
    2470             : 
    2471             :         X86Reg dstOp(X86Reg::fromSignature(cvtReg->getSignature(), cvtReg->getId()));
    2472             :         X86Reg srcOp(X86Reg::fromSignature(srcReg->getSignature(), srcReg->getId()));
    2473             : 
    2474             :         // Emit conversion after the prolog.
    2475           0 :         X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(_context->cc()),
    2476             :           dstOp, cvtReg->getTypeId(),
    2477           0 :           srcOp, srcReg->getTypeId(), _context->_avxEnabled);
    2478             :         srcReg = cvtReg;
    2479             :       }
    2480             : 
    2481           0 :       while (argMask != 0) {
    2482           0 :         if (argMask & 0x1) {
    2483           0 :           FuncDetail::Value& arg = fd.getArg(argIndex);
    2484             :           ASMJIT_ASSERT(arg.byStack());
    2485             : 
    2486           0 :           X86Mem dst = x86::ptr(_context->_zsp, -static_cast<int>(_context->getGpSize()) + arg.getStackOffset());
    2487           0 :           _context->emitRegToStack(arg.getTypeId(), &dst, srcReg->getTypeId(), srcReg->getPhysId());
    2488             :         }
    2489             : 
    2490           0 :         argIndex++;
    2491           0 :         argMask >>= 1;
    2492             :       }
    2493             :     }
    2494             : 
    2495             :     // Mark variables as modified.
    2496             :     modified<X86Reg::kKindGp>();
    2497             :     modified<X86Reg::kKindMm>();
    2498             :     modified<X86Reg::kKindVec>();
    2499             : 
    2500             :     // Cleanup; disconnect Vd->Va.
    2501             :     cleanup();
    2502             : 
    2503             :     // Update clobbered mask.
    2504       33050 :     _context->_clobberedRegs.or_(_willAlloc);
    2505             :   }
    2506             : 
    2507             :   // Update clobbered mask.
    2508       34994 :   _context->_clobberedRegs.or_(raData->clobberedRegs);
    2509             : 
    2510             :   // Unuse.
    2511       34994 :   if (raData->tiedTotal != 0) {
    2512             :     unuseAfter<X86Reg::kKindGp>();
    2513             :     unuseAfter<X86Reg::kKindMm>();
    2514             :     unuseAfter<X86Reg::kKindVec>();
    2515             :   }
    2516             : 
    2517             :   return kErrorOk;
    2518             : }
    2519             : 
    2520             : // ============================================================================
    2521             : // [asmjit::X86VarAlloc - Init / Cleanup]
    2522             : // ============================================================================
    2523             : 
    2524             : ASMJIT_INLINE void X86VarAlloc::init(CBNode* node, X86RAData* raData) {
    2525             :   X86BaseAlloc::init(node, raData);
    2526             : 
    2527             :   // These will block planner from assigning them during planning. Planner will
    2528             :   // add more registers when assigning registers to variables that don't need
    2529             :   // any specific register.
    2530       34994 :   _willAlloc = raData->inRegs;
    2531             :   _willAlloc.or_(raData->outRegs);
    2532             :   _willSpill.reset();
    2533             : }
    2534             : 
    2535             : ASMJIT_INLINE void X86VarAlloc::cleanup() {
    2536             :   X86BaseAlloc::cleanup();
    2537             : }
    2538             : 
    2539             : // ============================================================================
    2540             : // [asmjit::X86VarAlloc - Plan / Spill / Alloc]
    2541             : // ============================================================================
    2542             : 
    2543             : template<int C>
    2544             : ASMJIT_INLINE void X86VarAlloc::plan() {
    2545       46366 :   if (isTiedDone(C)) return;
    2546             : 
    2547             :   uint32_t i;
    2548             :   uint32_t willAlloc = _willAlloc.get(C);
    2549             :   uint32_t willFree = 0;
    2550             : 
    2551             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    2552             :   uint32_t tiedCount = getTiedCountByKind(C);
    2553             :   X86RAState* state = getState();
    2554             : 
    2555             :   // Calculate 'willAlloc' and 'willFree' masks based on mandatory masks.
    2556       95774 :   for (i = 0; i < tiedCount; i++) {
    2557       56656 :     TiedReg* tied = &tiedArray[i];
    2558       56656 :     VirtReg* vreg = tied->vreg;
    2559             : 
    2560       56656 :     uint32_t vaFlags = tied->flags;
    2561             :     uint32_t physId = vreg->getPhysId();
    2562       56656 :     uint32_t regMask = (physId != Globals::kInvalidRegId) ? Utils::mask(physId) : 0;
    2563             : 
    2564       56656 :     if ((vaFlags & TiedReg::kXReg) != 0) {
    2565             :       // Planning register allocation. First check whether the variable is
    2566             :       // already allocated in register and if it can stay allocated there.
    2567             :       //
    2568             :       // The following conditions may happen:
    2569             :       //
    2570             :       // a) Allocated register is one of the mandatoryRegs.
    2571             :       // b) Allocated register is one of the allocableRegs.
    2572       56656 :       uint32_t mandatoryRegs = tied->inRegs;
    2573       56656 :       uint32_t allocableRegs = tied->allocableRegs;
    2574             : 
    2575       56656 :       if (regMask != 0) {
    2576             :         // Special path for planning output-only registers.
    2577       30614 :         if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
    2578           0 :           uint32_t outPhysId = tied->outPhysId;
    2579           0 :           mandatoryRegs = (outPhysId != Globals::kInvalidRegId) ? Utils::mask(outPhysId) : 0;
    2580             : 
    2581           0 :           if ((mandatoryRegs | allocableRegs) & regMask) {
    2582             :             tied->setOutPhysId(physId);
    2583           0 :             tied->flags |= TiedReg::kWDone;
    2584             : 
    2585           0 :             if (mandatoryRegs & regMask) {
    2586             :               // Case 'a' - 'willAlloc' contains initially all inRegs from all TiedReg's.
    2587             :               ASMJIT_ASSERT((willAlloc & regMask) != 0);
    2588             :             }
    2589             :             else {
    2590             :               // Case 'b'.
    2591             :               tied->setOutPhysId(physId);
    2592           0 :               willAlloc |= regMask;
    2593             :             }
    2594             : 
    2595             :             addTiedDone(C);
    2596           0 :             continue;
    2597             :           }
    2598             :         }
    2599             :         else {
    2600       30614 :           if ((mandatoryRegs | allocableRegs) & regMask) {
    2601             :             tied->setInPhysId(physId);
    2602       30280 :             tied->flags |= TiedReg::kRDone;
    2603             : 
    2604       30280 :             if (mandatoryRegs & regMask) {
    2605             :               // Case 'a' - 'willAlloc' contains initially all inRegs from all TiedReg's.
    2606             :               ASMJIT_ASSERT((willAlloc & regMask) != 0);
    2607             :             }
    2608             :             else {
    2609             :               // Case 'b'.
    2610       28670 :               tied->inRegs |= regMask;
    2611       28670 :               willAlloc |= regMask;
    2612             :             }
    2613             : 
    2614             :             addTiedDone(C);
    2615       30280 :             continue;
    2616             :           }
    2617             :         }
    2618             :       }
    2619             : 
    2620             :       // Variable is not allocated or allocated in register that doesn't
    2621             :       // match inRegs or allocableRegs. The next step is to pick the best
    2622             :       // register for this variable. If `inRegs` contains any register the
    2623             :       // decision is simple - we have to follow, in other case will use
    2624             :       // the advantage of `guessAlloc()` to find a register (or registers)
    2625             :       // by looking ahead. But the best way to find a good register is not
    2626             :       // here since now we have no information about the registers that
    2627             :       // will be freed. So instead of finding register here, we just mark
    2628             :       // the current register (if variable is allocated) as `willFree` so
    2629             :       // the planner can use this information in the second step to plan the
    2630             :       // allocation as a whole.
    2631       26376 :       willFree |= regMask;
    2632       26376 :       continue;
    2633       26376 :     }
    2634             :     else {
    2635           0 :       if (regMask != 0) {
    2636           0 :         willFree |= regMask;
    2637           0 :         continue;
    2638             :       }
    2639             :       else {
    2640           0 :         tied->flags |= TiedReg::kRDone;
    2641             :         addTiedDone(C);
    2642           0 :         continue;
    2643             :       }
    2644             :     }
    2645             :   }
    2646             : 
    2647             :   // Occupied registers without 'willFree' registers; contains basically
    2648             :   // all the registers we can use to allocate variables without inRegs
    2649             :   // specified.
    2650       39118 :   uint32_t occupied = state->_occupied.get(C) & ~willFree;
    2651             :   uint32_t willSpill = 0;
    2652             : 
    2653             :   // Find the best registers for variables that are not allocated yet.
    2654       95774 :   for (i = 0; i < tiedCount; i++) {
    2655       56656 :     TiedReg* tied = &tiedArray[i];
    2656       56656 :     VirtReg* vreg = tied->vreg;
    2657       56656 :     uint32_t vaFlags = tied->flags;
    2658             : 
    2659       56656 :     if ((vaFlags & TiedReg::kXReg) != 0) {
    2660       56656 :       if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
    2661       22104 :         if (vaFlags & TiedReg::kWDone)
    2662           0 :           continue;
    2663             : 
    2664             :         // Skip all registers that have assigned outPhysId. Spill if occupied.
    2665       22104 :         if (tied->hasOutPhysId()) {
    2666           0 :           uint32_t outRegs = Utils::mask(tied->outPhysId);
    2667           0 :           willSpill |= occupied & outRegs;
    2668           0 :           continue;
    2669           0 :         }
    2670             :       }
    2671             :       else {
    2672       34552 :         if (vaFlags & TiedReg::kRDone)
    2673       30280 :           continue;
    2674             : 
    2675             :         // We skip all registers that have assigned inPhysId, indicates that
    2676             :         // the register to allocate in is known.
    2677        4272 :         if (tied->hasInPhysId()) {
    2678           0 :           uint32_t inRegs = tied->inRegs;
    2679           0 :           willSpill |= occupied & inRegs;
    2680           0 :           continue;
    2681           0 :         }
    2682             :       }
    2683             : 
    2684       26376 :       uint32_t m = tied->inRegs;
    2685       26376 :       if (tied->hasOutPhysId())
    2686           0 :         m |= Utils::mask(tied->outPhysId);
    2687             : 
    2688       26376 :       m = tied->allocableRegs & ~(willAlloc ^ m);
    2689             :       m = guessAlloc<C>(vreg, m);
    2690             :       ASMJIT_ASSERT(m != 0);
    2691             : 
    2692       26376 :       uint32_t candidateRegs = m & ~occupied;
    2693             :       uint32_t homeMask = vreg->getHomeMask();
    2694             : 
    2695             :       uint32_t physId;
    2696             :       uint32_t regMask;
    2697             : 
    2698       26376 :       if (candidateRegs == 0) {
    2699         138 :         candidateRegs = m & occupied & ~state->_modified.get(C);
    2700         138 :         if (candidateRegs == 0)
    2701             :           candidateRegs = m;
    2702             :       }
    2703       26376 :       if (candidateRegs & homeMask) candidateRegs &= homeMask;
    2704             : 
    2705             :       physId = Utils::findFirstBit(candidateRegs);
    2706             :       regMask = Utils::mask(physId);
    2707             : 
    2708       26376 :       if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
    2709             :         tied->setOutPhysId(physId);
    2710             :       }
    2711             :       else {
    2712             :         tied->setInPhysId(physId);
    2713        4272 :         tied->inRegs = regMask;
    2714             :       }
    2715             : 
    2716       26376 :       willAlloc |= regMask;
    2717       26376 :       willSpill |= regMask & occupied;
    2718             :       willFree  &=~regMask;
    2719       26376 :       occupied  |= regMask;
    2720             : 
    2721       26376 :       continue;
    2722       26376 :     }
    2723           0 :     else if ((vaFlags & TiedReg::kXMem) != 0) {
    2724             :       uint32_t physId = vreg->getPhysId();
    2725           0 :       if (physId != Globals::kInvalidRegId && (vaFlags & TiedReg::kXMem) != TiedReg::kWMem) {
    2726           0 :         willSpill |= Utils::mask(physId);
    2727             :       }
    2728             :     }
    2729             :   }
    2730             : 
    2731             :   // Set calculated masks back to the allocator; needed by spill() and alloc().
    2732             :   _willSpill.set(C, willSpill);
    2733             :   _willAlloc.set(C, willAlloc);
    2734             : }
    2735             : 
    2736             : template<int C>
    2737             : ASMJIT_INLINE void X86VarAlloc::spill() {
    2738             :   uint32_t m = _willSpill.get(C);
    2739             :   uint32_t i = static_cast<uint32_t>(0) - 1;
    2740       33050 :   if (m == 0) return;
    2741             : 
    2742             :   X86RAState* state = getState();
    2743             :   VirtReg** vregs = state->getListByKind(C);
    2744             : 
    2745             :   // Available registers for decision if move has any benefit over spill.
    2746             :   uint32_t availableRegs = getGaRegs(C) & ~(state->_occupied.get(C) | m | _willAlloc.get(C));
    2747             : 
    2748             :   do {
    2749             :     // We always advance one more to destroy the bit that we have found.
    2750         138 :     uint32_t bitIndex = Utils::findFirstBit(m) + 1;
    2751             : 
    2752         138 :     i += bitIndex;
    2753         138 :     m >>= bitIndex;
    2754             : 
    2755         138 :     VirtReg* vreg = vregs[i];
    2756             :     ASMJIT_ASSERT(vreg);
    2757             : 
    2758             :     TiedReg* tied = vreg->_tied;
    2759             :     ASMJIT_ASSERT(!tied || (tied->flags & TiedReg::kXReg) == 0);
    2760             : 
    2761             :     if (vreg->isModified() && availableRegs) {
    2762             :       // Don't check for alternatives if the variable has to be spilled.
    2763             :       if (!tied || (tied->flags & TiedReg::kSpill) == 0) {
    2764             :         uint32_t altRegs = guessSpill<C>(vreg, availableRegs);
    2765             : 
    2766             :         if (altRegs != 0) {
    2767             :           uint32_t physId = Utils::findFirstBit(altRegs);
    2768             :           uint32_t regMask = Utils::mask(physId);
    2769             : 
    2770             :           _context->move<C>(vreg, physId);
    2771             :           availableRegs ^= regMask;
    2772             :           continue;
    2773             :         }
    2774             :       }
    2775             :     }
    2776             : 
    2777         138 :     _context->spill<C>(vreg);
    2778         138 :   } while (m != 0);
    2779             : }
    2780             : 
    2781             : template<int C>
    2782             : ASMJIT_INLINE void X86VarAlloc::alloc() {
    2783       40298 :   if (isTiedDone(C)) return;
    2784             : 
    2785             :   uint32_t i;
    2786             :   bool didWork;
    2787             : 
    2788             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    2789             :   uint32_t tiedCount = getTiedCountByKind(C);
    2790             : 
    2791             :   // Alloc `in` regs.
    2792       29526 :   do {
    2793             :     didWork = false;
    2794       74516 :     for (i = 0; i < tiedCount; i++) {
    2795       44990 :       TiedReg* aTied = &tiedArray[i];
    2796       44990 :       VirtReg* aVReg = aTied->vreg;
    2797             : 
    2798       44990 :       if ((aTied->flags & (TiedReg::kRReg | TiedReg::kRDone)) != TiedReg::kRReg)
    2799       40718 :         continue;
    2800             : 
    2801             :       uint32_t aPhysId = aVReg->getPhysId();
    2802        4272 :       uint32_t bPhysId = aTied->inPhysId;
    2803             : 
    2804             :       // Shouldn't be the same.
    2805             :       ASMJIT_ASSERT(aPhysId != bPhysId);
    2806             : 
    2807        4272 :       VirtReg* bVReg = getState()->getListByKind(C)[bPhysId];
    2808        4272 :       if (bVReg) {
    2809             :         // Gp registers only - Swap two registers if we can solve two
    2810             :         // allocation tasks by a single 'xchg' instruction, swapping
    2811             :         // two registers required by the instruction/node or one register
    2812             :         // required with another non-required.
    2813           0 :         if (C == X86Reg::kKindGp && aPhysId != Globals::kInvalidRegId) {
    2814           0 :           TiedReg* bTied = bVReg->_tied;
    2815             :           _context->swapGp(aVReg, bVReg);
    2816             : 
    2817           0 :           aTied->flags |= TiedReg::kRDone;
    2818             :           addTiedDone(C);
    2819             : 
    2820             :           // Double-hit, two registers allocated by a single xchg.
    2821           0 :           if (bTied && bTied->inPhysId == aPhysId) {
    2822           0 :             bTied->flags |= TiedReg::kRDone;
    2823             :             addTiedDone(C);
    2824             :           }
    2825             : 
    2826             :           didWork = true;
    2827           0 :           continue;
    2828           0 :         }
    2829             :       }
    2830        4272 :       else if (aPhysId != Globals::kInvalidRegId) {
    2831             :         _context->move<C>(aVReg, bPhysId);
    2832             : 
    2833         334 :         aTied->flags |= TiedReg::kRDone;
    2834             :         addTiedDone(C);
    2835             : 
    2836             :         didWork = true;
    2837         334 :         continue;
    2838             :       }
    2839             :       else {
    2840             :         _context->alloc<C>(aVReg, bPhysId);
    2841             : 
    2842        3938 :         aTied->flags |= TiedReg::kRDone;
    2843             :         addTiedDone(C);
    2844             : 
    2845             :         didWork = true;
    2846        3938 :         continue;
    2847             :       }
    2848             :     }
    2849             :   } while (didWork);
    2850             : 
    2851             :   // Alloc 'out' regs.
    2852       62068 :   for (i = 0; i < tiedCount; i++) {
    2853       36814 :     TiedReg* tied = &tiedArray[i];
    2854       36814 :     VirtReg* vreg = tied->vreg;
    2855             : 
    2856       36814 :     if ((tied->flags & (TiedReg::kXReg | TiedReg::kWDone)) != TiedReg::kWReg)
    2857       14710 :       continue;
    2858             : 
    2859       22104 :     uint32_t physId = tied->outPhysId;
    2860             :     ASMJIT_ASSERT(physId != Globals::kInvalidRegId);
    2861             : 
    2862       22104 :     if (vreg->getPhysId() != physId) {
    2863             :       ASMJIT_ASSERT(getState()->getListByKind(C)[physId] == nullptr);
    2864       22104 :       _context->attach<C>(vreg, physId, false);
    2865             :     }
    2866             : 
    2867       22104 :     tied->flags |= TiedReg::kWDone;
    2868             :     addTiedDone(C);
    2869             :   }
    2870             : }
    2871             : 
    2872             : // ============================================================================
    2873             : // [asmjit::X86VarAlloc - GuessAlloc / GuessSpill]
    2874             : // ============================================================================
    2875             : 
    2876             : template<int C>
    2877             : ASMJIT_INLINE uint32_t X86VarAlloc::guessAlloc(VirtReg* vreg, uint32_t allocableRegs) {
    2878             :   ASMJIT_ASSERT(allocableRegs != 0);
    2879             : 
    2880             :   // Stop now if there is only one bit (register) set in `allocableRegs` mask.
    2881             :   if (Utils::isPowerOf2(allocableRegs)) return allocableRegs;
    2882             : 
    2883       26042 :   uint32_t raId = vreg->_raId;
    2884             :   uint32_t safeRegs = allocableRegs;
    2885             : 
    2886             :   uint32_t i;
    2887             :   uint32_t maxLookAhead = kCompilerDefaultLookAhead;
    2888             : 
    2889             :   // Look ahead and calculate mask of special registers on both - input/output.
    2890       26042 :   CBNode* node = _node;
    2891      118938 :   for (i = 0; i < maxLookAhead; i++) {
    2892             :     X86RAData* raData = node->getPassData<X86RAData>();
    2893      118866 :     RABits* liveness = raData ? raData->liveness : static_cast<RABits*>(nullptr);
    2894             : 
    2895             :     // If the variable becomes dead it doesn't make sense to continue.
    2896      118866 :     if (liveness && !liveness->getBit(raId)) break;
    2897             : 
    2898             :     // Stop on `CBSentinel` and `CCFuncRet`.
    2899       99048 :     if (node->hasFlag(CBNode::kFlagIsRet)) break;
    2900             : 
    2901             :     // Stop on conditional jump, we don't follow them.
    2902       99048 :     if (node->hasFlag(CBNode::kFlagIsJcc)) break;
    2903             : 
    2904             :     // Advance on non-conditional jump.
    2905       99048 :     if (node->hasFlag(CBNode::kFlagIsJmp)) {
    2906             :       node = static_cast<CBJump*>(node)->getTarget();
    2907             :       // Stop on jump that is not followed.
    2908           0 :       if (!node) break;
    2909             :     }
    2910             : 
    2911             :     node = node->getNext();
    2912             :     ASMJIT_ASSERT(node != nullptr);
    2913             : 
    2914             :     raData = node->getPassData<X86RAData>();
    2915       99048 :     if (raData) {
    2916             :       TiedReg* tied = raData->findTiedByKind(C, vreg);
    2917             :       uint32_t mask;
    2918             : 
    2919       99048 :       if (tied) {
    2920             :         // If the variable is overwritten it doesn't make sense to continue.
    2921       29868 :         if ((tied->flags & TiedReg::kRAll) == 0)
    2922             :           break;
    2923             : 
    2924       29868 :         mask = tied->allocableRegs;
    2925       29868 :         if (mask != 0) {
    2926       29868 :           allocableRegs &= mask;
    2927       29868 :           if (allocableRegs == 0) break;
    2928             :           safeRegs = allocableRegs;
    2929             :         }
    2930             : 
    2931       29212 :         mask = tied->inRegs;
    2932       29212 :         if (mask != 0) {
    2933        2092 :           allocableRegs &= mask;
    2934        2092 :           if (allocableRegs == 0) break;
    2935             :           safeRegs = allocableRegs;
    2936        2092 :           break;
    2937             :         }
    2938             : 
    2939       27120 :         allocableRegs &= ~(raData->outRegs.get(C) | raData->clobberedRegs.get(C));
    2940       27120 :         if (allocableRegs == 0) break;
    2941             :       }
    2942             :       else {
    2943       69180 :         allocableRegs &= ~(raData->inRegs.get(C) | raData->outRegs.get(C) | raData->clobberedRegs.get(C));
    2944       69180 :         if (allocableRegs == 0) break;
    2945             :       }
    2946             : 
    2947             :       safeRegs = allocableRegs;
    2948             :     }
    2949             :   }
    2950             : 
    2951             :   return safeRegs;
    2952             : }
    2953             : 
    2954             : template<int C>
    2955             : ASMJIT_INLINE uint32_t X86VarAlloc::guessSpill(VirtReg* vreg, uint32_t allocableRegs) {
    2956             :   ASMJIT_ASSERT(allocableRegs != 0);
    2957             : 
    2958             :   return 0;
    2959             : }
    2960             : 
    2961             : // ============================================================================
    2962             : // [asmjit::X86VarAlloc - Modified]
    2963             : // ============================================================================
    2964             : 
    2965             : template<int C>
    2966             : ASMJIT_INLINE void X86VarAlloc::modified() {
    2967             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    2968             :   uint32_t tiedCount = getTiedCountByKind(C);
    2969             : 
    2970       89706 :   for (uint32_t i = 0; i < tiedCount; i++) {
    2971       56656 :     TiedReg* tied = &tiedArray[i];
    2972             : 
    2973       56656 :     if (tied->flags & TiedReg::kWReg) {
    2974       30864 :       VirtReg* vreg = tied->vreg;
    2975             : 
    2976             :       uint32_t physId = vreg->getPhysId();
    2977             :       uint32_t regMask = Utils::mask(physId);
    2978             : 
    2979             :       vreg->setModified(true);
    2980       30864 :       _context->_x86State._modified.or_(C, regMask);
    2981             :     }
    2982             :   }
    2983             : }
    2984             : 
    2985             : // ============================================================================
    2986             : // [asmjit::X86CallAlloc]
    2987             : // ============================================================================
    2988             : 
    2989             : //! \internal
    2990             : //!
    2991             : //! Register allocator context (function call).
    2992             : struct X86CallAlloc : public X86BaseAlloc {
    2993             :   // --------------------------------------------------------------------------
    2994             :   // [Construction / Destruction]
    2995             :   // --------------------------------------------------------------------------
    2996             : 
    2997        1944 :   ASMJIT_INLINE X86CallAlloc(X86RAPass* context) : X86BaseAlloc(context) {}
    2998        1944 :   ASMJIT_INLINE ~X86CallAlloc() {}
    2999             : 
    3000             :   // --------------------------------------------------------------------------
    3001             :   // [Accessors]
    3002             :   // --------------------------------------------------------------------------
    3003             : 
    3004             :   //! Get the node.
    3005        1636 :   ASMJIT_INLINE CCFuncCall* getNode() const { return static_cast<CCFuncCall*>(_node); }
    3006             : 
    3007             :   // --------------------------------------------------------------------------
    3008             :   // [Run]
    3009             :   // --------------------------------------------------------------------------
    3010             : 
    3011             :   Error run(CCFuncCall* node);
    3012             : 
    3013             :   // --------------------------------------------------------------------------
    3014             :   // [Init / Cleanup]
    3015             :   // --------------------------------------------------------------------------
    3016             : 
    3017             : protected:
    3018             :   // Just to prevent calling these methods from X86RAPass::translate().
    3019             :   ASMJIT_INLINE void init(CCFuncCall* node, X86RAData* raData);
    3020             :   ASMJIT_INLINE void cleanup();
    3021             : 
    3022             :   // --------------------------------------------------------------------------
    3023             :   // [Plan / Alloc / Spill / Move]
    3024             :   // --------------------------------------------------------------------------
    3025             : 
    3026             :   template<int C>
    3027             :   ASMJIT_INLINE void plan();
    3028             : 
    3029             :   template<int C>
    3030             :   ASMJIT_INLINE void spill();
    3031             : 
    3032             :   template<int C>
    3033             :   ASMJIT_INLINE void alloc();
    3034             : 
    3035             :   // --------------------------------------------------------------------------
    3036             :   // [AllocImmsOnStack]
    3037             :   // --------------------------------------------------------------------------
    3038             : 
    3039             :   ASMJIT_INLINE void allocImmsOnStack();
    3040             : 
    3041             :   // --------------------------------------------------------------------------
    3042             :   // [Duplicate]
    3043             :   // --------------------------------------------------------------------------
    3044             : 
    3045             :   template<int C>
    3046             :   ASMJIT_INLINE void duplicate();
    3047             : 
    3048             :   // --------------------------------------------------------------------------
    3049             :   // [GuessAlloc / GuessSpill]
    3050             :   // --------------------------------------------------------------------------
    3051             : 
    3052             :   template<int C>
    3053             :   ASMJIT_INLINE uint32_t guessAlloc(VirtReg* vreg, uint32_t allocableRegs);
    3054             : 
    3055             :   template<int C>
    3056             :   ASMJIT_INLINE uint32_t guessSpill(VirtReg* vreg, uint32_t allocableRegs);
    3057             : 
    3058             :   // --------------------------------------------------------------------------
    3059             :   // [Save]
    3060             :   // --------------------------------------------------------------------------
    3061             : 
    3062             :   template<int C>
    3063             :   ASMJIT_INLINE void save();
    3064             : 
    3065             :   // --------------------------------------------------------------------------
    3066             :   // [Clobber]
    3067             :   // --------------------------------------------------------------------------
    3068             : 
    3069             :   template<int C>
    3070             :   ASMJIT_INLINE void clobber();
    3071             : 
    3072             :   // --------------------------------------------------------------------------
    3073             :   // [Ret]
    3074             :   // --------------------------------------------------------------------------
    3075             : 
    3076             :   ASMJIT_INLINE void ret();
    3077             : 
    3078             :   // --------------------------------------------------------------------------
    3079             :   // [Members]
    3080             :   // --------------------------------------------------------------------------
    3081             : 
    3082             :   //! Will alloc to these registers.
    3083             :   X86RegMask _willAlloc;
    3084             :   //! Will spill these registers.
    3085             :   X86RegMask _willSpill;
    3086             : };
    3087             : 
    3088             : // ============================================================================
    3089             : // [asmjit::X86CallAlloc - Run]
    3090             : // ============================================================================
    3091             : 
    3092        1636 : Error X86CallAlloc::run(CCFuncCall* node) {
    3093             :   // Initialize the allocator; prepare basics and connect Vd->Va.
    3094             :   X86RAData* raData = node->getPassData<X86RAData>();
    3095             :   init(node, raData);
    3096             : 
    3097             :   // Plan register allocation. Planner is only able to assign one register per
    3098             :   // variable. If any variable is used multiple times it will be handled later.
    3099             :   plan<X86Reg::kKindGp >();
    3100             :   plan<X86Reg::kKindMm >();
    3101             :   plan<X86Reg::kKindVec>();
    3102             : 
    3103             :   // Spill.
    3104             :   spill<X86Reg::kKindGp >();
    3105             :   spill<X86Reg::kKindMm >();
    3106             :   spill<X86Reg::kKindVec>();
    3107             : 
    3108             :   // Alloc.
    3109             :   alloc<X86Reg::kKindGp >();
    3110             :   alloc<X86Reg::kKindMm >();
    3111             :   alloc<X86Reg::kKindVec>();
    3112             : 
    3113             :   // Unuse clobbered registers that are not used to pass function arguments and
    3114             :   // save variables used to pass function arguments that will be reused later on.
    3115             :   save<X86Reg::kKindGp >();
    3116             :   save<X86Reg::kKindMm >();
    3117             :   save<X86Reg::kKindVec>();
    3118             : 
    3119             :   // Allocate immediates in registers and on the stack.
    3120             :   allocImmsOnStack();
    3121             : 
    3122             :   // Duplicate.
    3123             :   duplicate<X86Reg::kKindGp >();
    3124             :   duplicate<X86Reg::kKindMm >();
    3125             :   duplicate<X86Reg::kKindVec>();
    3126             : 
    3127             :   // Translate call operand.
    3128        1636 :   ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount()));
    3129             : 
    3130             :   // To emit instructions after call.
    3131        1636 :   _cc->_setCursor(node);
    3132             : 
    3133             :   // If the callee pops stack it has to be manually adjusted back.
    3134             :   FuncDetail& fd = node->getDetail();
    3135        1636 :   if (fd.hasFlag(CallConv::kFlagCalleePopsStack) && fd.getArgStackSize() != 0)
    3136           0 :     _cc->emit(X86Inst::kIdSub, _context->_zsp, static_cast<int>(fd.getArgStackSize()));
    3137             : 
    3138             :   // Clobber.
    3139             :   clobber<X86Reg::kKindGp >();
    3140             :   clobber<X86Reg::kKindMm >();
    3141             :   clobber<X86Reg::kKindVec>();
    3142             : 
    3143             :   // Return.
    3144             :   ret();
    3145             : 
    3146             :   // Unuse.
    3147             :   unuseAfter<X86Reg::kKindGp >();
    3148             :   unuseAfter<X86Reg::kKindMm >();
    3149             :   unuseAfter<X86Reg::kKindVec>();
    3150             : 
    3151             :   // Cleanup; disconnect Vd->Va.
    3152             :   cleanup();
    3153             : 
    3154             :   return kErrorOk;
    3155             : }
    3156             : 
    3157             : // ============================================================================
    3158             : // [asmjit::X86CallAlloc - Init / Cleanup]
    3159             : // ============================================================================
    3160             : 
    3161             : ASMJIT_INLINE void X86CallAlloc::init(CCFuncCall* node, X86RAData* raData) {
    3162             :   X86BaseAlloc::init(node, raData);
    3163             : 
    3164             :   // Create mask of all registers that will be used to pass function arguments.
    3165             :   _willAlloc.reset();
    3166             :   _willAlloc.set(X86Reg::kKindGp , node->getDetail().getUsedRegs(X86Reg::kKindGp ));
    3167             :   _willAlloc.set(X86Reg::kKindMm , node->getDetail().getUsedRegs(X86Reg::kKindMm ));
    3168             :   _willAlloc.set(X86Reg::kKindK  , node->getDetail().getUsedRegs(X86Reg::kKindK  ));
    3169             :   _willAlloc.set(X86Reg::kKindVec, node->getDetail().getUsedRegs(X86Reg::kKindVec));
    3170             :   _willSpill.reset();
    3171             : }
    3172             : 
    3173             : ASMJIT_INLINE void X86CallAlloc::cleanup() {
    3174             :   X86BaseAlloc::cleanup();
    3175             : }
    3176             : 
    3177             : // ============================================================================
    3178             : // [asmjit::X86CallAlloc - Plan / Spill / Alloc]
    3179             : // ============================================================================
    3180             : 
    3181             : template<int C>
    3182             : ASMJIT_INLINE void X86CallAlloc::plan() {
    3183             :   uint32_t i;
    3184        4908 :   uint32_t clobbered = _raData->clobberedRegs.get(C);
    3185             : 
    3186             :   uint32_t willAlloc = _willAlloc.get(C);
    3187        4908 :   uint32_t willFree = clobbered & ~willAlloc;
    3188             : 
    3189             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    3190             :   uint32_t tiedCount = getTiedCountByKind(C);
    3191             : 
    3192             :   X86RAState* state = getState();
    3193             : 
    3194             :   // Calculate 'willAlloc' and 'willFree' masks based on mandatory masks.
    3195        9626 :   for (i = 0; i < tiedCount; i++) {
    3196        4718 :     TiedReg* tied = &tiedArray[i];
    3197        4718 :     VirtReg* vreg = tied->vreg;
    3198             : 
    3199        4718 :     uint32_t vaFlags = tied->flags;
    3200             :     uint32_t physId = vreg->getPhysId();
    3201        4718 :     uint32_t regMask = (physId != Globals::kInvalidRegId) ? Utils::mask(physId) : 0;
    3202             : 
    3203        4718 :     if ((vaFlags & TiedReg::kRReg) != 0) {
    3204             :       // Planning register allocation. First check whether the variable is
    3205             :       // already allocated in register and if it can stay there. Function
    3206             :       // arguments are passed either in a specific register or in stack so
    3207             :       // we care mostly of mandatory registers.
    3208        3082 :       uint32_t inRegs = tied->inRegs;
    3209             : 
    3210        3082 :       if (inRegs == 0) {
    3211        1636 :         inRegs = tied->allocableRegs;
    3212             :       }
    3213             : 
    3214             :       // Optimize situation where the variable has to be allocated in a
    3215             :       // mandatory register, but it's already allocated in register that
    3216             :       // is not clobbered (i.e. it will survive function call).
    3217        3082 :       if ((regMask & inRegs) != 0 || ((regMask & ~clobbered) != 0 && (vaFlags & TiedReg::kUnuse) == 0)) {
    3218             :         tied->setInPhysId(physId);
    3219        2274 :         tied->flags |= TiedReg::kRDone;
    3220             :         addTiedDone(C);
    3221             :       }
    3222             :       else {
    3223         808 :         willFree |= regMask;
    3224             :       }
    3225             :     }
    3226             :     else {
    3227             :       // Memory access - if variable is allocated it has to be freed.
    3228        1636 :       if (regMask != 0) {
    3229           0 :         willFree |= regMask;
    3230             :       }
    3231             :       else {
    3232        1636 :         tied->flags |= TiedReg::kRDone;
    3233             :         addTiedDone(C);
    3234             :       }
    3235             :     }
    3236             :   }
    3237             : 
    3238             :   // Occupied registers without 'willFree' registers; contains basically
    3239             :   // all the registers we can use to allocate variables without inRegs
    3240             :   // speficied.
    3241        4908 :   uint32_t occupied = state->_occupied.get(C) & ~willFree;
    3242             :   uint32_t willSpill = 0;
    3243             : 
    3244             :   // Find the best registers for variables that are not allocated yet. Only
    3245             :   // useful for Gp registers used as call operand.
    3246        9626 :   for (i = 0; i < tiedCount; i++) {
    3247        4718 :     TiedReg* tied = &tiedArray[i];
    3248        1636 :     VirtReg* vreg = tied->vreg;
    3249             : 
    3250        4718 :     uint32_t vaFlags = tied->flags;
    3251        4718 :     if ((vaFlags & TiedReg::kRDone) != 0 || (vaFlags & TiedReg::kRReg) == 0)
    3252        3910 :       continue;
    3253             : 
    3254             :     // All registers except Gp used by call itself must have inPhysId.
    3255         808 :     uint32_t m = tied->inRegs;
    3256           0 :     if (C != X86Reg::kKindGp || m) {
    3257             :       ASMJIT_ASSERT(m != 0);
    3258             :       tied->setInPhysId(Utils::findFirstBit(m));
    3259         808 :       willSpill |= occupied & m;
    3260         808 :       continue;
    3261             :     }
    3262             : 
    3263           0 :     m = tied->allocableRegs & ~(willAlloc ^ m);
    3264             :     m = guessAlloc<C>(vreg, m);
    3265             :     ASMJIT_ASSERT(m != 0);
    3266             : 
    3267           0 :     uint32_t candidateRegs = m & ~occupied;
    3268           0 :     if (candidateRegs == 0) {
    3269           0 :       candidateRegs = m & occupied & ~state->_modified.get(C);
    3270           0 :       if (candidateRegs == 0)
    3271             :         candidateRegs = m;
    3272             :     }
    3273             : 
    3274           0 :     if (!(vaFlags & (TiedReg::kWReg | TiedReg::kUnuse)) && (candidateRegs & ~clobbered))
    3275             :       candidateRegs &= ~clobbered;
    3276             : 
    3277             :     uint32_t physId = Utils::findFirstBit(candidateRegs);
    3278             :     uint32_t regMask = Utils::mask(physId);
    3279             : 
    3280             :     tied->setInPhysId(physId);
    3281           0 :     tied->inRegs = regMask;
    3282             : 
    3283           0 :     willAlloc |= regMask;
    3284           0 :     willSpill |= regMask & occupied;
    3285             :     willFree &= ~regMask;
    3286             : 
    3287           0 :     occupied |= regMask;
    3288           0 :     continue;
    3289             :   }
    3290             : 
    3291             :   // Set calculated masks back to the allocator; needed by spill() and alloc().
    3292             :   _willSpill.set(C, willSpill);
    3293             :   _willAlloc.set(C, willAlloc);
    3294             : }
    3295             : 
    3296             : template<int C>
    3297             : ASMJIT_INLINE void X86CallAlloc::spill() {
    3298             :   uint32_t m = _willSpill.get(C);
    3299             :   uint32_t i = static_cast<uint32_t>(0) - 1;
    3300             : 
    3301        1636 :   if (m == 0)
    3302             :     return;
    3303             : 
    3304             :   X86RAState* state = getState();
    3305             :   VirtReg** sVars = state->getListByKind(C);
    3306             : 
    3307             :   // Available registers for decision if move has any benefit over spill.
    3308             :   uint32_t availableRegs = getGaRegs(C) & ~(state->_occupied.get(C) | m | _willAlloc.get(C));
    3309             : 
    3310             :   do {
    3311             :     // We always advance one more to destroy the bit that we have found.
    3312         410 :     uint32_t bitIndex = Utils::findFirstBit(m) + 1;
    3313             : 
    3314         410 :     i += bitIndex;
    3315         410 :     m >>= bitIndex;
    3316             : 
    3317         410 :     VirtReg* vreg = sVars[i];
    3318             :     ASMJIT_ASSERT(vreg && !vreg->_tied);
    3319             : 
    3320             :     if (vreg->isModified() && availableRegs) {
    3321             :       uint32_t available = guessSpill<C>(vreg, availableRegs);
    3322             :       if (available != 0) {
    3323             :         uint32_t physId = Utils::findFirstBit(available);
    3324             :         uint32_t regMask = Utils::mask(physId);
    3325             : 
    3326             :         _context->move<C>(vreg, physId);
    3327             :         availableRegs ^= regMask;
    3328             :         continue;
    3329             :       }
    3330             :     }
    3331             : 
    3332         410 :     _context->spill<C>(vreg);
    3333         410 :   } while (m != 0);
    3334             : }
    3335             : 
    3336             : template<int C>
    3337             : ASMJIT_INLINE void X86CallAlloc::alloc() {
    3338        1636 :   if (isTiedDone(C)) return;
    3339             : 
    3340             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    3341             :   uint32_t tiedCount = getTiedCountByKind(C);
    3342             : 
    3343             :   uint32_t i;
    3344             :   bool didWork;
    3345             : 
    3346        1616 :   do {
    3347             :     didWork = false;
    3348        4872 :     for (i = 0; i < tiedCount; i++) {
    3349        3256 :       TiedReg* aTied = &tiedArray[i];
    3350        3256 :       VirtReg* aVReg = aTied->vreg;
    3351        3256 :       if ((aTied->flags & (TiedReg::kRReg | TiedReg::kRDone)) != TiedReg::kRReg) continue;
    3352             : 
    3353             :       uint32_t sPhysId = aVReg->getPhysId();
    3354         808 :       uint32_t bPhysId = aTied->inPhysId;
    3355             : 
    3356             :       // Shouldn't be the same.
    3357             :       ASMJIT_ASSERT(sPhysId != bPhysId);
    3358             : 
    3359         808 :       VirtReg* bVReg = getState()->getListByKind(C)[bPhysId];
    3360         808 :       if (bVReg) {
    3361           0 :         TiedReg* bTied = bVReg->_tied;
    3362             : 
    3363             :         // GP registers only - Swap two registers if we can solve two
    3364             :         // allocation tasks by a single 'xchg' instruction, swapping
    3365             :         // two registers required by the instruction/node or one register
    3366             :         // required with another non-required.
    3367             :         if (C == X86Reg::kKindGp) {
    3368             :           _context->swapGp(aVReg, bVReg);
    3369             : 
    3370           0 :           aTied->flags |= TiedReg::kRDone;
    3371             :           addTiedDone(C);
    3372             : 
    3373             :           // Double-hit, two registers allocated by a single swap.
    3374           0 :           if (bTied && bTied->inPhysId == sPhysId) {
    3375           0 :             bTied->flags |= TiedReg::kRDone;
    3376             :             addTiedDone(C);
    3377             :           }
    3378             : 
    3379             :           didWork = true;
    3380           0 :           continue;
    3381             :         }
    3382           0 :       }
    3383         808 :       else if (sPhysId != Globals::kInvalidRegId) {
    3384             :         _context->move<C>(aVReg, bPhysId);
    3385         322 :         _context->_clobberedRegs.or_(C, Utils::mask(bPhysId));
    3386             : 
    3387         322 :         aTied->flags |= TiedReg::kRDone;
    3388             :         addTiedDone(C);
    3389             : 
    3390             :         didWork = true;
    3391         322 :         continue;
    3392             :       }
    3393             :       else {
    3394             :         _context->alloc<C>(aVReg, bPhysId);
    3395         486 :         _context->_clobberedRegs.or_(C, Utils::mask(bPhysId));
    3396             : 
    3397         486 :         aTied->flags |= TiedReg::kRDone;
    3398             :         addTiedDone(C);
    3399             : 
    3400             :         didWork = true;
    3401         486 :         continue;
    3402             :       }
    3403             :     }
    3404             :   } while (didWork);
    3405             : }
    3406             : 
    3407             : // ============================================================================
    3408             : // [asmjit::X86CallAlloc - AllocImmsOnStack]
    3409             : // ============================================================================
    3410             : 
    3411             : ASMJIT_INLINE void X86CallAlloc::allocImmsOnStack() {
    3412             :   CCFuncCall* node = getNode();
    3413             :   FuncDetail& fd = node->getDetail();
    3414             : 
    3415             :   uint32_t argCount = fd.getArgCount();
    3416        1636 :   Operand_* args = node->_args;
    3417             : 
    3418        3486 :   for (uint32_t i = 0; i < argCount; i++) {
    3419        1850 :     Operand_& op = args[i];
    3420        1850 :     if (!op.isImm()) continue;
    3421             : 
    3422             :     const Imm& imm = static_cast<const Imm&>(op);
    3423             :     const FuncDetail::Value& arg = fd.getArg(i);
    3424             :     uint32_t varType = arg.getTypeId();
    3425             : 
    3426         404 :     if (arg.byReg()) {
    3427         404 :       _context->emitImmToReg(varType, arg.getRegId(), &imm);
    3428             :     }
    3429             :     else {
    3430           0 :       X86Mem dst = x86::ptr(_context->_zsp, -static_cast<int>(_context->getGpSize()) + arg.getStackOffset());
    3431           0 :       _context->emitImmToStack(varType, &dst, &imm);
    3432             :     }
    3433             :   }
    3434             : }
    3435             : 
    3436             : // ============================================================================
    3437             : // [asmjit::X86CallAlloc - Duplicate]
    3438             : // ============================================================================
    3439             : 
    3440             : template<int C>
    3441             : ASMJIT_INLINE void X86CallAlloc::duplicate() {
    3442             :   TiedReg* tiedArray = getTiedArrayByKind(C);
    3443             :   uint32_t tiedCount = getTiedCountByKind(C);
    3444             : 
    3445        6354 :   for (uint32_t i = 0; i < tiedCount; i++) {
    3446        4718 :     TiedReg* tied = &tiedArray[i];
    3447        4718 :     if ((tied->flags & TiedReg::kRReg) == 0) continue;
    3448             : 
    3449        3082 :     uint32_t inRegs = tied->inRegs;
    3450        3082 :     if (!inRegs) continue;
    3451             : 
    3452        1446 :     VirtReg* vreg = tied->vreg;
    3453             :     uint32_t physId = vreg->getPhysId();
    3454             : 
    3455             :     ASMJIT_ASSERT(physId != Globals::kInvalidRegId);
    3456             : 
    3457        1446 :     inRegs &= ~Utils::mask(physId);
    3458        1446 :     if (!inRegs) continue;
    3459             : 
    3460           0 :     for (uint32_t dupIndex = 0; inRegs != 0; dupIndex++, inRegs >>= 1) {
    3461           0 :       if (inRegs & 0x1) {
    3462           0 :         _context->emitMove(vreg, dupIndex, physId, "Duplicate");
    3463           0 :         _context->_clobberedRegs.or_(C, Utils::mask(dupIndex));
    3464             :       }
    3465             :     }
    3466             :   }
    3467             : }
    3468             : 
    3469             : // ============================================================================
    3470             : // [asmjit::X86CallAlloc - GuessAlloc / GuessSpill]
    3471             : // ============================================================================
    3472             : 
    3473             : template<int C>
    3474             : ASMJIT_INLINE uint32_t X86CallAlloc::guessAlloc(VirtReg* vreg, uint32_t allocableRegs) {
    3475             :   ASMJIT_ASSERT(allocableRegs != 0);
    3476             : 
    3477             :   // Stop now if there is only one bit (register) set in 'allocableRegs' mask.
    3478             :   if (Utils::isPowerOf2(allocableRegs))
    3479             :     return allocableRegs;
    3480             : 
    3481             :   uint32_t i;
    3482             :   uint32_t safeRegs = allocableRegs;
    3483             :   uint32_t maxLookAhead = kCompilerDefaultLookAhead;
    3484             : 
    3485             :   // Look ahead and calculate mask of special registers on both - input/output.
    3486           0 :   CBNode* node = _node;
    3487           0 :   for (i = 0; i < maxLookAhead; i++) {
    3488             :     // Stop on `CCFuncRet` and `CBSentinel`.
    3489           0 :     if (node->hasFlag(CBNode::kFlagIsRet))
    3490             :       break;
    3491             : 
    3492             :     // Stop on conditional jump, we don't follow them.
    3493           0 :     if (node->hasFlag(CBNode::kFlagIsJcc))
    3494             :       break;
    3495             : 
    3496             :     // Advance on non-conditional jump.
    3497           0 :     if (node->hasFlag(CBNode::kFlagIsJmp)) {
    3498             :       node = static_cast<CBJump*>(node)->getTarget();
    3499             :       // Stop on jump that is not followed.
    3500           0 :       if (!node) break;
    3501             :     }
    3502             : 
    3503             :     node = node->getNext();
    3504             :     ASMJIT_ASSERT(node != nullptr);
    3505             : 
    3506             :     X86RAData* raData = node->getPassData<X86RAData>();
    3507           0 :     if (raData) {
    3508             :       TiedReg* tied = raData->findTiedByKind(C, vreg);
    3509           0 :       if (tied) {
    3510           0 :         uint32_t inRegs = tied->inRegs;
    3511           0 :         if (inRegs != 0) {
    3512             :           safeRegs = allocableRegs;
    3513           0 :           allocableRegs &= inRegs;
    3514             : 
    3515           0 :           if (allocableRegs == 0)
    3516           0 :             goto _UseSafeRegs;
    3517             :           else
    3518             :             return allocableRegs;
    3519             :         }
    3520             :       }
    3521             : 
    3522             :       safeRegs = allocableRegs;
    3523           0 :       allocableRegs &= ~(raData->inRegs.get(C) | raData->outRegs.get(C) | raData->clobberedRegs.get(C));
    3524             : 
    3525           0 :       if (allocableRegs == 0)
    3526             :         break;
    3527             :     }
    3528             :   }
    3529             : 
    3530           0 : _UseSafeRegs:
    3531             :   return safeRegs;
    3532             : }
    3533             : 
    3534             : template<int C>
    3535             : ASMJIT_INLINE uint32_t X86CallAlloc::guessSpill(VirtReg* vreg, uint32_t allocableRegs) {
    3536             :   ASMJIT_ASSERT(allocableRegs != 0);
    3537             :   return 0;
    3538             : }
    3539             : 
    3540             : // ============================================================================
    3541             : // [asmjit::X86CallAlloc - Save]
    3542             : // ============================================================================
    3543             : 
    3544             : template<int C>
    3545             : ASMJIT_INLINE void X86CallAlloc::save() {
    3546             :   X86RAState* state = getState();
    3547             :   VirtReg** sVars = state->getListByKind(C);
    3548             : 
    3549             :   uint32_t i;
    3550        4908 :   uint32_t affected = _raData->clobberedRegs.get(C) & state->_occupied.get(C) & state->_modified.get(C);
    3551             : 
    3552        6444 :   for (i = 0; affected != 0; i++, affected >>= 1) {
    3553        4808 :     if (affected & 0x1) {
    3554        3936 :       VirtReg* vreg = sVars[i];
    3555             :       ASMJIT_ASSERT(vreg != nullptr);
    3556             :       ASMJIT_ASSERT(vreg->isModified());
    3557             : 
    3558        3936 :       TiedReg* tied = vreg->_tied;
    3559        3936 :       if (!tied || (tied->flags & (TiedReg::kWReg | TiedReg::kUnuse)) == 0)
    3560        3468 :         _context->save<C>(vreg);
    3561             :     }
    3562             :   }
    3563             : }
    3564             : 
    3565             : // ============================================================================
    3566             : // [asmjit::X86CallAlloc - Clobber]
    3567             : // ============================================================================
    3568             : 
    3569             : template<int C>
    3570             : ASMJIT_INLINE void X86CallAlloc::clobber() {
    3571             :   X86RAState* state = getState();
    3572             :   VirtReg** sVars = state->getListByKind(C);
    3573             : 
    3574             :   uint32_t i;
    3575        4908 :   uint32_t affected = _raData->clobberedRegs.get(C) & state->_occupied.get(C);
    3576             : 
    3577        6870 :   for (i = 0; affected != 0; i++, affected >>= 1) {
    3578        5234 :     if (affected & 0x1) {
    3579        4830 :       VirtReg* vreg = sVars[i];
    3580             :       ASMJIT_ASSERT(vreg != nullptr);
    3581             : 
    3582        4830 :       TiedReg* tied = vreg->_tied;
    3583             :       uint32_t vdState = VirtReg::kStateNone;
    3584             : 
    3585        4830 :       if (!vreg->isModified() || (tied && (tied->flags & (TiedReg::kWAll | TiedReg::kUnuse)) != 0))
    3586             :         vdState = VirtReg::kStateMem;
    3587        4830 :       _context->unuse<C>(vreg, vdState);
    3588             :     }
    3589             :   }
    3590             : }
    3591             : 
    3592             : // ============================================================================
    3593             : // [asmjit::X86CallAlloc - Ret]
    3594             : // ============================================================================
    3595             : 
    3596             : ASMJIT_INLINE void X86CallAlloc::ret() {
    3597             :   CCFuncCall* node = getNode();
    3598             :   FuncDetail& fd = node->getDetail();
    3599        1636 :   Operand_* rets = node->_ret;
    3600             : 
    3601        4908 :   for (uint32_t i = 0; i < 2; i++) {
    3602        3272 :     const FuncDetail::Value& ret = fd.getRet(i);
    3603        3272 :     Operand_* op = &rets[i];
    3604             : 
    3605        3272 :     if (!ret.byReg() || !op->isVirtReg())
    3606        1636 :       continue;
    3607             : 
    3608        1636 :     VirtReg* vreg = _cc->getVirtRegById(op->getId());
    3609             :     uint32_t regId = ret.getRegId();
    3610             : 
    3611        1636 :     switch (vreg->getKind()) {
    3612           0 :       case X86Reg::kKindGp:
    3613           0 :         _context->unuse<X86Reg::kKindGp>(vreg);
    3614           0 :         _context->attach<X86Reg::kKindGp>(vreg, regId, true);
    3615             :         break;
    3616             : 
    3617           0 :       case X86Reg::kKindMm:
    3618           0 :         _context->unuse<X86Reg::kKindMm>(vreg);
    3619           0 :         _context->attach<X86Reg::kKindMm>(vreg, regId, true);
    3620             :         break;
    3621             : 
    3622             :       case X86Reg::kKindVec:
    3623        1636 :         if (X86Reg::kindOf(ret.getRegType()) == X86Reg::kKindVec) {
    3624        1636 :           _context->unuse<X86Reg::kKindVec>(vreg);
    3625        1636 :           _context->attach<X86Reg::kKindVec>(vreg, regId, true);
    3626             :         }
    3627             :         else {
    3628             :           uint32_t elementId = TypeId::elementOf(vreg->getTypeId());
    3629           0 :           uint32_t size = (elementId == TypeId::kF32) ? 4 : 8;
    3630             : 
    3631           0 :           X86Mem m = _context->getVarMem(vreg);
    3632             :           m.setSize(size);
    3633             : 
    3634           0 :           _context->unuse<X86Reg::kKindVec>(vreg, VirtReg::kStateMem);
    3635           0 :           _cc->fstp(m);
    3636             :         }
    3637             :         break;
    3638             :     }
    3639             :   }
    3640             : }
    3641             : 
    3642             : // ============================================================================
    3643             : // [asmjit::X86RAPass - TranslateOperands]
    3644             : // ============================================================================
    3645             : 
    3646             : //! \internal
    3647       32742 : static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount) {
    3648             :   X86Compiler* cc = self->cc();
    3649             : 
    3650             :   // Translate variables into registers.
    3651       96710 :   for (uint32_t i = 0; i < opCount; i++) {
    3652       63968 :     Operand_* op = &opArray[i];
    3653             :     if (op->isVirtReg()) {
    3654             :       VirtReg* vreg = cc->getVirtRegById(op->getId());
    3655             :       ASMJIT_ASSERT(vreg != nullptr);
    3656             :       ASMJIT_ASSERT(vreg->getPhysId() != Globals::kInvalidRegId);
    3657       50532 :       op->_reg.id = vreg->getPhysId();
    3658             :     }
    3659       13436 :     else if (op->isMem()) {
    3660             :       X86Mem* m = static_cast<X86Mem*>(op);
    3661             : 
    3662        6068 :       if (m->hasBaseReg() && cc->isVirtRegValid(m->getBaseId())) {
    3663             :         VirtReg* vreg = cc->getVirtRegById(m->getBaseId());
    3664             : 
    3665        6068 :         if (m->isRegHome()) {
    3666           0 :           self->getVarCell(vreg);
    3667             :         }
    3668             :         else {
    3669             :           ASMJIT_ASSERT(vreg->getPhysId() != Globals::kInvalidRegId);
    3670        6068 :           op->_mem.base = vreg->getPhysId();
    3671             :         }
    3672             :       }
    3673             : 
    3674        6068 :       if (m->hasIndexReg() && cc->isVirtRegValid(m->getIndexId())) {
    3675             :         VirtReg* vreg = cc->getVirtRegById(m->getIndexId());
    3676           0 :         op->_mem.index = vreg->getPhysId();
    3677             :       }
    3678             :     }
    3679             :   }
    3680             : 
    3681       32742 :   return kErrorOk;
    3682             : }
    3683             : 
    3684             : // ============================================================================
    3685             : // [asmjit::X86RAPass - TranslatePrologEpilog]
    3686             : // ============================================================================
    3687             : 
    3688             : //! \internal
    3689        1944 : static Error X86RAPass_prepareFuncFrame(X86RAPass* self, CCFunc* func) {
    3690             :   FuncFrameInfo& ffi = func->getFrameInfo();
    3691             : 
    3692             :   X86RegMask& clobberedRegs = self->_clobberedRegs;
    3693             : 
    3694             :   // Initialize dirty registers.
    3695             :   ffi.setDirtyRegs(X86Reg::kKindGp , clobberedRegs.get(X86Reg::kKindGp ));
    3696             :   ffi.setDirtyRegs(X86Reg::kKindMm , clobberedRegs.get(X86Reg::kKindMm ));
    3697             :   ffi.setDirtyRegs(X86Reg::kKindK  , clobberedRegs.get(X86Reg::kKindK  ));
    3698             :   ffi.setDirtyRegs(X86Reg::kKindVec, clobberedRegs.get(X86Reg::kKindVec));
    3699             : 
    3700             :   // Initialize stack size & alignment.
    3701        1944 :   ffi.setStackFrameSize(self->_memAllTotal);
    3702        1944 :   ffi.setStackFrameAlignment(self->_memMaxAlign);
    3703             : 
    3704        1944 :   return kErrorOk;
    3705             : }
    3706             : 
    3707             : //! \internal
    3708        1944 : static Error X86RAPass_patchFuncMem(X86RAPass* self, CCFunc* func, CBNode* stop, FuncFrameLayout& layout) {
    3709             :   X86Compiler* cc = self->cc();
    3710             :   CBNode* node = func;
    3711             : 
    3712             :   do {
    3713       50006 :     if (node->getType() == CBNode::kNodeInst) {
    3714             :       CBInst* iNode = static_cast<CBInst*>(node);
    3715             : 
    3716       40594 :       if (iNode->hasMemOp()) {
    3717             :         X86Mem* m = iNode->getMemOp<X86Mem>();
    3718             : 
    3719       14496 :         if (m->isArgHome()) {
    3720             :           m->addOffsetLo32(layout.getStackArgsOffset());
    3721             :           m->clearArgHome();
    3722             :         }
    3723             : 
    3724       14496 :         if (m->isRegHome() && Operand::isPackedId(m->getBaseId())) {
    3725             :           VirtReg* vreg = cc->getVirtRegById(m->getBaseId());
    3726             :           ASMJIT_ASSERT(vreg != nullptr);
    3727             : 
    3728             :           RACell* cell = vreg->getMemCell();
    3729             :           ASMJIT_ASSERT(cell != nullptr);
    3730             : 
    3731        8428 :           m->_setBase(cc->_nativeGpReg.getType(), self->_varBaseRegId);
    3732        8428 :           m->addOffsetLo32(self->_varBaseOffset + cell->offset);
    3733             :           m->clearRegHome();
    3734             :         }
    3735             :       }
    3736             :     }
    3737             : 
    3738             :     node = node->getNext();
    3739       50006 :   } while (node != stop);
    3740             : 
    3741        1944 :   return kErrorOk;
    3742             : }
    3743             : 
    3744             : // ============================================================================
    3745             : // [asmjit::X86RAPass - Translate - Jump]
    3746             : // ============================================================================
    3747             : 
    3748             : //! \internal
    3749           0 : static void X86RAPass_translateJump(X86RAPass* self, CBJump* jNode, CBLabel* jTarget) {
    3750             :   X86Compiler* cc = self->cc();
    3751             : 
    3752             :   CBNode* injectRef = self->getFunc()->getEnd()->getPrev();
    3753           0 :   CBNode* prevCursor = cc->setCursor(injectRef);
    3754             : 
    3755           0 :   self->switchState(jTarget->getPassData<RAData>()->state);
    3756             : 
    3757             :   // Any code necessary to `switchState()` will be added at the end of the function.
    3758           0 :   if (cc->getCursor() != injectRef) {
    3759             :     // TODO: Can fail.
    3760           0 :     CBLabel* injectLabel = cc->newLabelNode();
    3761             : 
    3762             :     // Add the jump to the target.
    3763           0 :     cc->jmp(jTarget->getLabel());
    3764             : 
    3765             :     // Inject the label.
    3766             :     cc->_setCursor(injectRef);
    3767           0 :     cc->addNode(injectLabel);
    3768             : 
    3769             :     // Finally, patch `jNode` target.
    3770             :     ASMJIT_ASSERT(jNode->getOpCount() > 0);
    3771           0 :     jNode->_opArray[jNode->getOpCount() - 1] = injectLabel->getLabel();
    3772           0 :     jNode->_target = injectLabel;
    3773             :     // If we injected any code it may not satisfy short form anymore.
    3774             :     jNode->delOptions(X86Inst::kOptionShortForm);
    3775             :   }
    3776             : 
    3777             :   cc->_setCursor(prevCursor);
    3778           0 :   self->loadState(jNode->getPassData<RAData>()->state);
    3779           0 : }
    3780             : 
    3781             : // ============================================================================
    3782             : // [asmjit::X86RAPass - Translate - Ret]
    3783             : // ============================================================================
    3784             : 
    3785        1944 : static Error X86RAPass_translateRet(X86RAPass* self, CCFuncRet* rNode, CBLabel* exitTarget) {
    3786             :   X86Compiler* cc = self->cc();
    3787             :   CBNode* node = rNode->getNext();
    3788             : 
    3789             :   // 32-bit mode requires to push floating point return value(s), handle it
    3790             :   // here as it's a special case.
    3791             :   X86RAData* raData = rNode->getPassData<X86RAData>();
    3792        1944 :   if (raData) {
    3793        1944 :     TiedReg* tiedArray = raData->tiedArray;
    3794        1944 :     uint32_t tiedTotal = raData->tiedTotal;
    3795             : 
    3796        3888 :     for (uint32_t i = 0; i < tiedTotal; i++) {
    3797        1944 :       TiedReg* tied = &tiedArray[i];
    3798        1944 :       if (tied->flags & (TiedReg::kX86Fld4 | TiedReg::kX86Fld8)) {
    3799           0 :         VirtReg* vreg = tied->vreg;
    3800             :         X86Mem m(self->getVarMem(vreg));
    3801             : 
    3802             :         uint32_t elementId = TypeId::elementOf(vreg->getTypeId());
    3803           0 :         m.setSize(elementId == TypeId::kF32 ? 4 :
    3804             :                   elementId == TypeId::kF64 ? 8 :
    3805           0 :                   (tied->flags & TiedReg::kX86Fld4) ? 4 : 8);
    3806             : 
    3807             :         cc->fld(m);
    3808             :       }
    3809             :     }
    3810             :   }
    3811             : 
    3812             :   // Decide whether to `jmp` or not in case we are next to the return label.
    3813        1944 :   while (node) {
    3814        1944 :     switch (node->getType()) {
    3815             :       // If we have found an exit label we just return, there is no need to
    3816             :       // emit jump to that.
    3817        1944 :       case CBNode::kNodeLabel:
    3818        1944 :         if (static_cast<CBLabel*>(node) == exitTarget)
    3819             :           return kErrorOk;
    3820           0 :         goto _EmitRet;
    3821             : 
    3822           0 :       case CBNode::kNodeData:
    3823             :       case CBNode::kNodeInst:
    3824             :       case CBNode::kNodeFuncCall:
    3825             :       case CBNode::kNodeFuncExit:
    3826           0 :         goto _EmitRet;
    3827             : 
    3828             :       // Continue iterating.
    3829             :       case CBNode::kNodeComment:
    3830             :       case CBNode::kNodeAlign:
    3831             :       case CBNode::kNodeHint:
    3832             :         break;
    3833             : 
    3834             :       // Invalid node to be here.
    3835             :       case CBNode::kNodeFunc:
    3836             :         return DebugUtils::errored(kErrorInvalidState);
    3837             : 
    3838             :       // We can't go forward from here.
    3839           0 :       case CBNode::kNodeSentinel:
    3840           0 :         return kErrorOk;
    3841             :     }
    3842             : 
    3843             :     node = node->getNext();
    3844             :   }
    3845             : 
    3846           0 : _EmitRet:
    3847             :   {
    3848             :     cc->_setCursor(rNode);
    3849           0 :     cc->jmp(exitTarget->getLabel());
    3850             :   }
    3851           0 :   return kErrorOk;
    3852             : }
    3853             : 
    3854             : // ============================================================================
    3855             : // [asmjit::X86RAPass - Translate - Func]
    3856             : // ============================================================================
    3857             : 
    3858        1944 : Error X86RAPass::translate() {
    3859             :   X86Compiler* cc = this->cc();
    3860             :   CCFunc* func = getFunc();
    3861             : 
    3862             :   // Register allocator contexts.
    3863             :   X86VarAlloc vAlloc(this);
    3864             :   X86CallAlloc cAlloc(this);
    3865             : 
    3866             :   // Flow.
    3867             :   CBNode* node_ = func;
    3868             :   CBNode* next = nullptr;
    3869             :   CBNode* stop = getStop();
    3870             : 
    3871             :   ZoneList<CBNode*>::Link* jLink = _jccList.getFirst();
    3872             : 
    3873             :   for (;;) {
    3874       36630 :     while (node_->isTranslated()) {
    3875             :       // Switch state if we went to a node that is already translated.
    3876           0 :       if (node_->getType() == CBNode::kNodeLabel) {
    3877             :         CBLabel* node = static_cast<CBLabel*>(node_);
    3878             :         cc->_setCursor(node->getPrev());
    3879           0 :         switchState(node->getPassData<RAData>()->state);
    3880             :       }
    3881             : 
    3882           0 : _NextGroup:
    3883        1944 :       if (!jLink) {
    3884        1944 :         goto _Done;
    3885             :       }
    3886             :       else {
    3887             :         node_ = jLink->getValue();
    3888             :         jLink = jLink->getNext();
    3889             : 
    3890             :         CBNode* jFlow = X86RAPass_getOppositeJccFlow(static_cast<CBJump*>(node_));
    3891           0 :         loadState(node_->getPassData<RAData>()->state);
    3892             : 
    3893           0 :         if (jFlow->hasPassData() && jFlow->getPassData<RAData>()->state) {
    3894           0 :           X86RAPass_translateJump(this, static_cast<CBJump*>(node_), static_cast<CBLabel*>(jFlow));
    3895             : 
    3896             :           node_ = jFlow;
    3897           0 :           if (node_->isTranslated())
    3898           0 :             goto _NextGroup;
    3899             :         }
    3900             :         else {
    3901             :           node_ = jFlow;
    3902             :         }
    3903             : 
    3904             :         break;
    3905             :       }
    3906             :     }
    3907             : 
    3908             :     next = node_->getNext();
    3909       36630 :     node_->_flags |= CBNode::kFlagIsTranslated;
    3910             : 
    3911       36630 :     if (node_->hasPassData()) {
    3912       36630 :       switch (node_->getType()) {
    3913             :         // --------------------------------------------------------------------
    3914             :         // [Align / Embed]
    3915             :         // --------------------------------------------------------------------
    3916             : 
    3917             :         case CBNode::kNodeAlign:
    3918             :         case CBNode::kNodeData:
    3919             :           break;
    3920             : 
    3921             :         // --------------------------------------------------------------------
    3922             :         // [Label]
    3923             :         // --------------------------------------------------------------------
    3924             : 
    3925           0 :         case CBNode::kNodeLabel: {
    3926             :           CBLabel* node = static_cast<CBLabel*>(node_);
    3927             :           ASMJIT_ASSERT(node->getPassData<RAData>()->state == nullptr);
    3928           0 :           node->getPassData<RAData>()->state = saveState();
    3929             : 
    3930           0 :           if (node == func->getExitNode())
    3931           0 :             goto _NextGroup;
    3932             :           break;
    3933             :         }
    3934             : 
    3935             :         // --------------------------------------------------------------------
    3936             :         // [Inst/Call/SArg/Ret]
    3937             :         // --------------------------------------------------------------------
    3938             : 
    3939             :         case CBNode::kNodeInst:
    3940             :         case CBNode::kNodeFunc:
    3941             :         case CBNode::kNodeFuncCall:
    3942             :         case CBNode::kNodePushArg:
    3943             :           // Update TiedReg's unuse flags based on liveness of the next node.
    3944       34686 :           if (!node_->isJcc()) {
    3945             :             X86RAData* raData = node_->getPassData<X86RAData>();
    3946             :             RABits* liveness;
    3947             : 
    3948       34686 :             if (raData && next && next->hasPassData() && (liveness = next->getPassData<RAData>()->liveness)) {
    3949       34686 :               TiedReg* tiedArray = raData->tiedArray;
    3950       34686 :               uint32_t tiedTotal = raData->tiedTotal;
    3951             : 
    3952       94116 :               for (uint32_t i = 0; i < tiedTotal; i++) {
    3953       59430 :                 TiedReg* tied = &tiedArray[i];
    3954       59430 :                 VirtReg* vreg = tied->vreg;
    3955             : 
    3956       59430 :                 if (!liveness->getBit(vreg->_raId) && !vreg->isFixed())
    3957       21796 :                   tied->flags |= TiedReg::kUnuse;
    3958             :               }
    3959             :             }
    3960             :           }
    3961             : 
    3962       34686 :           if (node_->getType() == CBNode::kNodeFuncCall) {
    3963        1636 :             ASMJIT_PROPAGATE(cAlloc.run(static_cast<CCFuncCall*>(node_)));
    3964             :             break;
    3965             :           }
    3966             :           ASMJIT_FALLTHROUGH;
    3967             : 
    3968             :         case CBNode::kNodeHint:
    3969             :         case CBNode::kNodeFuncExit: {
    3970       34994 :           ASMJIT_PROPAGATE(vAlloc.run(node_));
    3971             : 
    3972             :           // Handle conditional/unconditional jump.
    3973       34994 :           if (node_->isJmpOrJcc()) {
    3974             :             CBJump* node = static_cast<CBJump*>(node_);
    3975             :             CBLabel* jTarget = node->getTarget();
    3976             : 
    3977             :             // Target not followed.
    3978           0 :             if (!jTarget) {
    3979           0 :               if (node->isJmp())
    3980           0 :                 goto _NextGroup;
    3981             :               else
    3982             :                 break;
    3983             :             }
    3984             : 
    3985           0 :             if (node->isJmp()) {
    3986           0 :               if (jTarget->hasPassData() && jTarget->getPassData<RAData>()->state) {
    3987             :                 cc->_setCursor(node->getPrev());
    3988           0 :                 switchState(jTarget->getPassData<RAData>()->state);
    3989             : 
    3990           0 :                 goto _NextGroup;
    3991             :               }
    3992             :               else {
    3993             :                 next = jTarget;
    3994             :               }
    3995             :             }
    3996             :             else {
    3997             :               CBNode* jNext = node->getNext();
    3998             : 
    3999           0 :               if (jTarget->isTranslated()) {
    4000           0 :                 if (jNext->isTranslated()) {
    4001             :                   ASMJIT_ASSERT(jNext->getType() == CBNode::kNodeLabel);
    4002             :                   cc->_setCursor(node->getPrev());
    4003           0 :                   intersectStates(
    4004             :                     jTarget->getPassData<RAData>()->state,
    4005             :                     jNext->getPassData<RAData>()->state);
    4006             :                 }
    4007             : 
    4008           0 :                 RAState* savedState = saveState();
    4009           0 :                 node->getPassData<RAData>()->state = savedState;
    4010             : 
    4011           0 :                 X86RAPass_translateJump(this, node, jTarget);
    4012             :                 next = jNext;
    4013             :               }
    4014           0 :               else if (jNext->isTranslated()) {
    4015             :                 ASMJIT_ASSERT(jNext->getType() == CBNode::kNodeLabel);
    4016             : 
    4017           0 :                 RAState* savedState = saveState();
    4018           0 :                 node->getPassData<RAData>()->state = savedState;
    4019             : 
    4020             :                 cc->_setCursor(node);
    4021           0 :                 switchState(jNext->getPassData<RAData>()->state);
    4022             :                 next = jTarget;
    4023             :               }
    4024             :               else {
    4025           0 :                 node->getPassData<RAData>()->state = saveState();
    4026             :                 next = X86RAPass_getJccFlow(node);
    4027             :               }
    4028             :             }
    4029             :           }
    4030       34994 :           else if (node_->isRet()) {
    4031        1944 :             ASMJIT_PROPAGATE(
    4032             :               X86RAPass_translateRet(this, static_cast<CCFuncRet*>(node_), func->getExitNode()));
    4033        1944 :             goto _NextGroup;
    4034             :           }
    4035             :           break;
    4036             :         }
    4037             : 
    4038             :         // --------------------------------------------------------------------
    4039             :         // [End]
    4040             :         // --------------------------------------------------------------------
    4041             : 
    4042           0 :         case CBNode::kNodeSentinel: {
    4043           0 :           goto _NextGroup;
    4044             :         }
    4045             : 
    4046             :         default:
    4047             :           break;
    4048             :       }
    4049             :     }
    4050             : 
    4051       34686 :     if (next == stop)
    4052           0 :       goto _NextGroup;
    4053             :     node_ = next;
    4054             :   }
    4055             : 
    4056             : _Done:
    4057             :   {
    4058        1944 :     ASMJIT_PROPAGATE(resolveCellOffsets());
    4059        1944 :     ASMJIT_PROPAGATE(X86RAPass_prepareFuncFrame(this, func));
    4060             : 
    4061             :     FuncFrameLayout layout;
    4062        1944 :     ASMJIT_PROPAGATE(layout.init(func->getDetail(), func->getFrameInfo()));
    4063             : 
    4064        1944 :     _varBaseRegId = layout._stackBaseRegId;
    4065        1944 :     _varBaseOffset = layout._stackBaseOffset;
    4066             : 
    4067        1944 :     ASMJIT_PROPAGATE(X86RAPass_patchFuncMem(this, func, stop, layout));
    4068             : 
    4069             :     cc->_setCursor(func);
    4070        1944 :     ASMJIT_PROPAGATE(FuncUtils::emitProlog(this->cc(), layout));
    4071             : 
    4072             :     cc->_setCursor(func->getExitNode());
    4073        1944 :     ASMJIT_PROPAGATE(FuncUtils::emitEpilog(this->cc(), layout));
    4074             :   }
    4075             : 
    4076        1944 :   return kErrorOk;
    4077             : }
    4078             : 
    4079             : } // asmjit namespace
    4080             : } // namespace PLMD
    4081             : 
    4082             : // [Api-End]
    4083             : #include "./asmjit_apiend.h"
    4084             : 
    4085             : // [Guard]
    4086             : #endif // ASMJIT_BUILD_X86 && !ASMJIT_DISABLE_COMPILER
    4087             : #pragma GCC diagnostic pop
    4088             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.15