LCOV - code coverage report
Current view: top level - asmjit - func.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 68 97 70.1 %
Date: 2024-10-11 08:09:49 Functions: 0 0 -

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifndef __PLUMED_asmjit_func_h
      21             : #define __PLUMED_asmjit_func_h
      22             : #ifdef __PLUMED_HAS_ASMJIT
      23             : #pragma GCC diagnostic push
      24             : #pragma GCC diagnostic ignored "-Wpedantic"
      25             : // [AsmJit]
      26             : // Complete x86/x64 JIT and Remote Assembler for C++.
      27             : //
      28             : // [License]
      29             : // Zlib - See LICENSE.md file in the package.
      30             : 
      31             : // [Guard]
      32             : #ifndef _ASMJIT_BASE_FUNC_H
      33             : #define _ASMJIT_BASE_FUNC_H
      34             : 
      35             : #include "./asmjit_build.h"
      36             : 
      37             : // [Dependencies]
      38             : #include "./arch.h"
      39             : #include "./operand.h"
      40             : #include "./utils.h"
      41             : 
      42             : // [Api-Begin]
      43             : #include "./asmjit_apibegin.h"
      44             : 
      45             : namespace PLMD {
      46             : namespace asmjit {
      47             : 
      48             : //! \addtogroup asmjit_base
      49             : //! \{
      50             : 
      51             : // ============================================================================
      52             : // [Forward Declarations]
      53             : // ============================================================================
      54             : 
      55             : class CodeEmitter;
      56             : 
      57             : // ============================================================================
      58             : // [asmjit::CallConv]
      59             : // ============================================================================
      60             : 
      61             : //! Function calling convention.
      62             : //!
      63             : //! Function calling convention is a scheme that defines how function parameters
      64             : //! are passed and how function returns its result. AsmJit defines a variety of
      65             : //! architecture and OS specific calling conventions and also provides a compile
      66             : //! time detection to make JIT code-generation easier.
      67             : struct CallConv {
      68             :   //! Calling convention id.
      69             :   ASMJIT_ENUM(Id) {
      70             :     //! None or invalid (can't be used).
      71             :     kIdNone = 0,
      72             : 
      73             :     // ------------------------------------------------------------------------
      74             :     // [Universal]
      75             :     // ------------------------------------------------------------------------
      76             : 
      77             :     // TODO: To make this possible we need to know target ARCH and ABI.
      78             : 
      79             :     /*
      80             : 
      81             :     // Universal calling conventions are applicable to any target and are
      82             :     // converted to target dependent conventions at runtime. The purpose of
      83             :     // these conventions is to make using functions less target dependent.
      84             : 
      85             :     kIdCDecl = 1,
      86             :     kIdStdCall = 2,
      87             :     kIdFastCall = 3,
      88             : 
      89             :     //! AsmJit specific calling convention designed for calling functions
      90             :     //! inside a multimedia code like that don't use many registers internally,
      91             :     //! but are long enough to be called and not inlined. These functions are
      92             :     //! usually used to calculate trigonometric functions, logarithms, etc...
      93             :     kIdFastEval2 = 10,
      94             :     kIdFastEval3 = 11,
      95             :     kIdFastEval4 = 12,
      96             :     */
      97             : 
      98             :     // ------------------------------------------------------------------------
      99             :     // [X86]
     100             :     // ------------------------------------------------------------------------
     101             : 
     102             :     //! X86 `__cdecl` calling convention (used by C runtime and libraries).
     103             :     kIdX86CDecl = 16,
     104             :     //! X86 `__stdcall` calling convention (used mostly by WinAPI).
     105             :     kIdX86StdCall = 17,
     106             :     //! X86 `__thiscall` calling convention (MSVC/Intel).
     107             :     kIdX86MsThisCall = 18,
     108             :     //! X86 `__fastcall` convention (MSVC/Intel).
     109             :     kIdX86MsFastCall = 19,
     110             :     //! X86 `__fastcall` convention (GCC and Clang).
     111             :     kIdX86GccFastCall = 20,
     112             :     //! X86 `regparm(1)` convention (GCC and Clang).
     113             :     kIdX86GccRegParm1 = 21,
     114             :     //! X86 `regparm(2)` convention (GCC and Clang).
     115             :     kIdX86GccRegParm2 = 22,
     116             :     //! X86 `regparm(3)` convention (GCC and Clang).
     117             :     kIdX86GccRegParm3 = 23,
     118             : 
     119             :     kIdX86FastEval2 = 29,
     120             :     kIdX86FastEval3 = 30,
     121             :     kIdX86FastEval4 = 31,
     122             : 
     123             :     //! X64 calling convention defined by WIN64-ABI.
     124             :     //!
     125             :     //! Links:
     126             :     //!   * <http://msdn.microsoft.com/en-us/library/9b372w95.aspx>.
     127             :     kIdX86Win64 = 32,
     128             :     //! X64 calling convention used by Unix platforms (SYSV/AMD64-ABI).
     129             :     kIdX86SysV64 = 33,
     130             : 
     131             :     kIdX64FastEval2 = 45,
     132             :     kIdX64FastEval3 = 46,
     133             :     kIdX64FastEval4 = 47,
     134             : 
     135             :     // ------------------------------------------------------------------------
     136             :     // [ARM]
     137             :     // ------------------------------------------------------------------------
     138             : 
     139             :     //! Legacy calling convention, floating point arguments are passed via GP registers.
     140             :     kIdArm32SoftFP = 48,
     141             :     //! Modern calling convention, uses VFP registers to pass floating point arguments.
     142             :     kIdArm32HardFP = 49,
     143             : 
     144             :     // ------------------------------------------------------------------------
     145             :     // [Internal]
     146             :     // ------------------------------------------------------------------------
     147             : 
     148             :     _kIdX86Start = 16,   //!< \internal
     149             :     _kIdX86End = 31,     //!< \internal
     150             : 
     151             :     _kIdX64Start = 32,  //!< \internal
     152             :     _kIdX64End = 47,    //!< \internal
     153             : 
     154             :     _kIdArmStart = 48,  //!< \internal
     155             :     _kIdArmEnd = 49,    //!< \internal
     156             : 
     157             :     // ------------------------------------------------------------------------
     158             :     // [Host]
     159             :     // ------------------------------------------------------------------------
     160             : 
     161             : #if defined(ASMJIT_DOCGEN)
     162             :     //! Default calling convention based on the current C++ compiler's settings.
     163             :     //!
     164             :     //! NOTE: This should be always the same as `kIdHostCDecl`, but some
     165             :     //! compilers allow to override the default calling convention. Overriding
     166             :     //! is not detected at the moment.
     167             :     kIdHost          = DETECTED_AT_COMPILE_TIME,
     168             : 
     169             :     //! Default CDECL calling convention based on the current C++ compiler's settings.
     170             :     kIdHostCDecl     = DETECTED_AT_COMPILE_TIME,
     171             : 
     172             :     //! Default STDCALL calling convention based on the current C++ compiler's settings.
     173             :     //!
     174             :     //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`.
     175             :     kIdHostStdCall   = DETECTED_AT_COMPILE_TIME,
     176             : 
     177             :     //! Compatibility for `__fastcall` calling convention.
     178             :     //!
     179             :     //! NOTE: If not defined by the host then it's the same as `kIdHostCDecl`.
     180             :     kIdHostFastCall  = DETECTED_AT_COMPILE_TIME
     181             : #elif ASMJIT_ARCH_X86
     182             :     kIdHost          = kIdX86CDecl,
     183             :     kIdHostCDecl     = kIdX86CDecl,
     184             :     kIdHostStdCall   = kIdX86StdCall,
     185             :     kIdHostFastCall  = ASMJIT_CC_MSC   ? kIdX86MsFastCall  :
     186             :                        ASMJIT_CC_GCC   ? kIdX86GccFastCall :
     187             :                        ASMJIT_CC_CLANG ? kIdX86GccFastCall : kIdNone,
     188             :     kIdHostFastEval2 = kIdX86FastEval2,
     189             :     kIdHostFastEval3 = kIdX86FastEval3,
     190             :     kIdHostFastEval4 = kIdX86FastEval4
     191             : #elif ASMJIT_ARCH_X64
     192             :     kIdHost          = ASMJIT_OS_WINDOWS ? kIdX86Win64 : kIdX86SysV64,
     193             :     kIdHostCDecl     = kIdHost, // Doesn't exist, redirected to host.
     194             :     kIdHostStdCall   = kIdHost, // Doesn't exist, redirected to host.
     195             :     kIdHostFastCall  = kIdHost, // Doesn't exist, redirected to host.
     196             :     kIdHostFastEval2 = kIdX64FastEval2,
     197             :     kIdHostFastEval3 = kIdX64FastEval3,
     198             :     kIdHostFastEval4 = kIdX64FastEval4
     199             : #elif ASMJIT_ARCH_ARM32
     200             : # if defined(__SOFTFP__)
     201             :     kIdHost          = kIdArm32SoftFP,
     202             : # else
     203             :     kIdHost          = kIdArm32HardFP,
     204             : # endif
     205             :     // These don't exist on ARM.
     206             :     kIdHostCDecl     = kIdHost, // Doesn't exist, redirected to host.
     207             :     kIdHostStdCall   = kIdHost, // Doesn't exist, redirected to host.
     208             :     kIdHostFastCall  = kIdHost  // Doesn't exist, redirected to host.
     209             : #else
     210             : # error "[asmjit] Couldn't determine the target's calling convention."
     211             : #endif
     212             :   };
     213             : 
     214             :   //! Calling convention algorithm.
     215             :   //!
     216             :   //! This is AsmJit specific. It basically describes how should AsmJit convert
     217             :   //! the function arguments defined by `FuncSignature` into register ids or
     218             :   //! stack offsets. The default algorithm is a standard algorithm that assigns
     219             :   //! registers first, and then assigns stack. The Win64 algorithm does register
     220             :   //! shadowing as defined by `WIN64` calling convention - it applies to 64-bit
     221             :   //! calling conventions only.
     222             :   ASMJIT_ENUM(Algorithm) {
     223             :     kAlgorithmDefault    = 0,            //!< Default algorithm (cross-platform).
     224             :     kAlgorithmWin64      = 1             //!< WIN64 specific algorithm.
     225             :   };
     226             : 
     227             :   //! Calling convention flags.
     228             :   ASMJIT_ENUM(Flags) {
     229             :     kFlagCalleePopsStack = 0x01,         //!< Callee is responsible for cleaning up the stack.
     230             :     kFlagPassFloatsByVec = 0x02,         //!< Pass F32 and F64 arguments by VEC128 register.
     231             :     kFlagVectorCall      = 0x04,         //!< This is a '__vectorcall' calling convention.
     232             :     kFlagIndirectVecArgs = 0x08          //!< Pass vector arguments indirectly (as a pointer).
     233             :   };
     234             : 
     235             :   //! Internal limits of AsmJit/CallConv.
     236             :   ASMJIT_ENUM(Limits) {
     237             :     kMaxVRegKinds        = Globals::kMaxVRegKinds,
     238             :     kNumRegArgsPerKind   = 8
     239             :   };
     240             : 
     241             :   //! Passed registers' order.
     242             :   union RegOrder {
     243             :     uint8_t id[kNumRegArgsPerKind];      //!< Passed registers, ordered.
     244             :     uint32_t packed[(kNumRegArgsPerKind + 3) / 4];
     245             :   };
     246             : 
     247             :   // --------------------------------------------------------------------------
     248             :   // [Utilities]
     249             :   // --------------------------------------------------------------------------
     250             : 
     251        3580 :   static ASMJIT_INLINE bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; }
     252             :   static ASMJIT_INLINE bool isArmFamily(uint32_t ccId) noexcept { return ccId >= _kIdArmStart && ccId <= _kIdArmEnd; }
     253             : 
     254             :   // --------------------------------------------------------------------------
     255             :   // [Init / Reset]
     256             :   // --------------------------------------------------------------------------
     257             : 
     258             :   ASMJIT_API Error init(uint32_t ccId) noexcept;
     259             : 
     260             :   ASMJIT_INLINE void reset() noexcept {
     261             :     ::memset(this, 0, sizeof(*this));
     262        3580 :     ::memset(_passedOrder, 0xFF, sizeof(_passedOrder));
     263             :   }
     264             : 
     265             :   // --------------------------------------------------------------------------
     266             :   // [Accessors]
     267             :   // --------------------------------------------------------------------------
     268             : 
     269             :   //! Get calling convention id, see \ref Id.
     270        1944 :   ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
     271             :   //! Set calling convention id, see \ref Id.
     272        3580 :   ASMJIT_INLINE void setId(uint32_t id) noexcept { _id = static_cast<uint8_t>(id); }
     273             : 
     274             :   //! Get architecture type.
     275        5524 :   ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archType; }
     276             :   //! Set architecture type.
     277        3580 :   ASMJIT_INLINE void setArchType(uint32_t archType) noexcept { _archType = static_cast<uint8_t>(archType); }
     278             : 
     279             :   //! Get calling convention algorithm, see \ref Algorithm.
     280        3580 :   ASMJIT_INLINE uint32_t getAlgorithm() const noexcept { return _algorithm; }
     281             :   //! Set calling convention algorithm, see \ref Algorithm.
     282           0 :   ASMJIT_INLINE void setAlgorithm(uint32_t algorithm) noexcept { _algorithm = static_cast<uint8_t>(algorithm); }
     283             : 
     284             :   //! Get if the calling convention has the given `flag` set.
     285        5026 :   ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
     286             :   //! Get calling convention flags, see \ref Flags.
     287             :   ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
     288             :   //! Add calling convention flags, see \ref Flags.
     289           0 :   ASMJIT_INLINE void setFlags(uint32_t flag) noexcept { _flags = flag; };
     290             :   //! Add calling convention flags, see \ref Flags.
     291             :   ASMJIT_INLINE void addFlags(uint32_t flag) noexcept { _flags |= flag; };
     292             : 
     293             :   //! Get a natural stack alignment.
     294        5832 :   ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _naturalStackAlignment; }
     295             : 
     296             :   //! Set a natural stack alignment.
     297             :   //!
     298             :   //! This function can be used to override the default stack alignment in case
     299             :   //! that you know that it's alignment is different. For example it allows to
     300             :   //! implement custom calling conventions that guarantee higher stack alignment.
     301             :   ASMJIT_INLINE void setNaturalStackAlignment(uint32_t value) noexcept {
     302             :     ASMJIT_ASSERT(value < 256);
     303        3580 :     _naturalStackAlignment = static_cast<uint8_t>(value);
     304           0 :   }
     305             : 
     306             :   //! Get if this calling convention specifies 'SpillZone'.
     307             :   ASMJIT_INLINE bool hasSpillZone() const noexcept { return _spillZoneSize != 0; }
     308             :   //! Get size of 'SpillZone'.
     309        1944 :   ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; }
     310             :   //! Set size of 'SpillZone'.
     311           0 :   ASMJIT_INLINE void setSpillZoneSize(uint32_t size) noexcept { _spillZoneSize = static_cast<uint8_t>(size); }
     312             : 
     313             :   //! Get if this calling convention specifies 'RedZone'.
     314             :   ASMJIT_INLINE bool hasRedZone() const noexcept { return _redZoneSize != 0; }
     315             :   //! Get size of 'RedZone'.
     316             :   ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; }
     317             :   //! Set size of 'RedZone'.
     318        3580 :   ASMJIT_INLINE void setRedZoneSize(uint32_t size) noexcept { _redZoneSize = static_cast<uint16_t>(size); }
     319             : 
     320             :   ASMJIT_INLINE const uint8_t* getPassedOrder(uint32_t kind) const noexcept {
     321             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     322             :     return _passedOrder[kind].id;
     323             :   }
     324             : 
     325             :   ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept {
     326             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     327       11356 :     return _passedRegs[kind];
     328             :   }
     329             : 
     330             :   ASMJIT_INLINE void _setPassedPacked(uint32_t kind, uint32_t p0, uint32_t p1) noexcept {
     331             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     332             : 
     333        3580 :     _passedOrder[kind].packed[0] = p0;
     334        3580 :     _passedOrder[kind].packed[1] = p1;
     335             :   }
     336             : 
     337             :   ASMJIT_INLINE void setPassedToNone(uint32_t kind) noexcept {
     338             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     339             : 
     340             :     _setPassedPacked(kind, ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF),
     341             :                            ASMJIT_PACK32_4x8(0xFF, 0xFF, 0xFF, 0xFF));
     342             :     _passedRegs[kind] = 0;
     343             :   }
     344             : 
     345             :   ASMJIT_INLINE void setPassedOrder(uint32_t kind, uint32_t a0, uint32_t a1 = 0xFF, uint32_t a2 = 0xFF, uint32_t a3 = 0xFF, uint32_t a4 = 0xFF, uint32_t a5 = 0xFF, uint32_t a6 = 0xFF, uint32_t a7 = 0xFF) noexcept {
     346             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     347             : 
     348             :     _setPassedPacked(kind, ASMJIT_PACK32_4x8(a0, a1, a2, a3),
     349             :                            ASMJIT_PACK32_4x8(a4, a5, a6, a7));
     350             : 
     351             :     // NOTE: This should always be called with all arguments known at compile
     352             :     // time, so even if it looks scary it should be translated to a single
     353             :     // instruction.
     354           0 :     _passedRegs[kind] = (a0 != 0xFF ? 1U << a0 : 0U) |
     355             :                         (a1 != 0xFF ? 1U << a1 : 0U) |
     356             :                         (a2 != 0xFF ? 1U << a2 : 0U) |
     357             :                         (a3 != 0xFF ? 1U << a3 : 0U) |
     358             :                         (a4 != 0xFF ? 1U << a4 : 0U) |
     359             :                         (a5 != 0xFF ? 1U << a5 : 0U) |
     360             :                         (a6 != 0xFF ? 1U << a6 : 0U) |
     361             :                         (a7 != 0xFF ? 1U << a7 : 0U) ;
     362             :   }
     363             : 
     364             :   ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept {
     365             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     366        9412 :     return _preservedRegs[kind];
     367             :   }
     368             : 
     369             : 
     370             :   ASMJIT_INLINE void setPreservedRegs(uint32_t kind, uint32_t regs) noexcept {
     371             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     372           0 :     _preservedRegs[kind] = regs;
     373        3580 :   }
     374             : 
     375             :   // --------------------------------------------------------------------------
     376             :   // [Members]
     377             :   // --------------------------------------------------------------------------
     378             : 
     379             :   uint8_t _id;                           //!< Calling convention id, see \ref Id.
     380             :   uint8_t _archType;                     //!< Architecture type (see \ref ArchInfo::Type).
     381             :   uint8_t _algorithm;                    //!< Calling convention algorithm.
     382             :   uint8_t _flags;                        //!< Calling convention flags.
     383             : 
     384             :   uint8_t _naturalStackAlignment;        //!< Natural stack alignment as defined by OS/ABI.
     385             :   uint8_t _spillZoneSize;                //!< Spill zone size (WIN64 == 32 bytes).
     386             :   uint16_t _redZoneSize;                 //!< Red zone size (AMD64 == 128 bytes).
     387             : 
     388             :   RegOrder _passedOrder[kMaxVRegKinds];  //!< Passed registers' order, per kind.
     389             :   uint32_t _passedRegs[kMaxVRegKinds];   //!< Mask of all passed registers, per kind.
     390             :   uint32_t _preservedRegs[kMaxVRegKinds];//!< Mask of all preserved registers, per kind.
     391             : };
     392             : 
     393             : // ============================================================================
     394             : // [asmjit::FuncArgIndex]
     395             : // ============================================================================
     396             : 
     397             : //! Function argument index (lo/hi).
     398             : ASMJIT_ENUM(FuncArgIndex) {
     399             :   //! Maximum number of function arguments supported by AsmJit.
     400             :   kFuncArgCount = 16,
     401             :   //! Extended maximum number of arguments (used internally).
     402             :   kFuncArgCountLoHi = kFuncArgCount * 2,
     403             : 
     404             :   //! Index to the LO part of function argument (default).
     405             :   //!
     406             :   //! This value is typically omitted and added only if there is HI argument
     407             :   //! accessed.
     408             :   kFuncArgLo = 0,
     409             : 
     410             :   //! Index to the HI part of function argument.
     411             :   //!
     412             :   //! HI part of function argument depends on target architecture. On x86 it's
     413             :   //! typically used to transfer 64-bit integers (they form a pair of 32-bit
     414             :   //! integers).
     415             :   kFuncArgHi = kFuncArgCount
     416             : };
     417             : 
     418             : // ============================================================================
     419             : // [asmjit::FuncSignature]
     420             : // ============================================================================
     421             : 
     422             : //! Function signature.
     423             : //!
     424             : //! Contains information about function return type, count of arguments and
     425             : //! their TypeIds. Function signature is a low level structure which doesn't
     426             : //! contain platform specific or calling convention specific information.
     427             : struct FuncSignature {
     428             :   enum {
     429             :     //! Doesn't have variable number of arguments (`...`).
     430             :     kNoVarArgs = 0xFF
     431             :   };
     432             : 
     433             :   // --------------------------------------------------------------------------
     434             :   // [Init / Reset]
     435             :   // --------------------------------------------------------------------------
     436             : 
     437             :   //! Initialize the function signature.
     438             :   ASMJIT_INLINE void init(uint32_t ccId, uint32_t ret, const uint8_t* args, uint32_t argCount) noexcept {
     439             :     ASMJIT_ASSERT(ccId <= 0xFF);
     440             :     ASMJIT_ASSERT(argCount <= 0xFF);
     441             : 
     442        3580 :     _callConv = static_cast<uint8_t>(ccId);
     443        3580 :     _argCount = static_cast<uint8_t>(argCount);
     444        3580 :     _vaIndex = kNoVarArgs;
     445        3580 :     _ret = ret;
     446        3580 :     _args = args;
     447             :   }
     448             : 
     449             :   ASMJIT_INLINE void reset() noexcept {
     450             :     memset(this, 0, sizeof(*this));
     451             :   }
     452             : 
     453             :   // --------------------------------------------------------------------------
     454             :   // [Accessors]
     455             :   // --------------------------------------------------------------------------
     456             : 
     457             :   //! Get the function's calling convention.
     458        3580 :   ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; }
     459             : 
     460             :   //! Get if the function has variable number of arguments (...).
     461             :   ASMJIT_INLINE bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; }
     462             :   //! Get the variable arguments (...) index, `kNoVarArgs` if none.
     463             :   ASMJIT_INLINE uint32_t getVAIndex() const noexcept { return _vaIndex; }
     464             : 
     465             :   //! Get the number of function arguments.
     466        5216 :   ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; }
     467             : 
     468             :   ASMJIT_INLINE bool hasRet() const noexcept { return _ret != TypeId::kVoid; }
     469             :   //! Get the return value type.
     470        3580 :   ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; }
     471             : 
     472             :   //! Get the type of the argument at index `i`.
     473             :   ASMJIT_INLINE uint32_t getArg(uint32_t i) const noexcept {
     474             :     ASMJIT_ASSERT(i < _argCount);
     475             :     return _args[i];
     476             :   }
     477             :   //! Get the array of function arguments' types.
     478        3580 :   ASMJIT_INLINE const uint8_t* getArgs() const noexcept { return _args; }
     479             : 
     480             :   // --------------------------------------------------------------------------
     481             :   // [Members]
     482             :   // --------------------------------------------------------------------------
     483             : 
     484             :   uint8_t _callConv;                     //!< Calling convention id.
     485             :   uint8_t _argCount;                     //!< Count of arguments.
     486             :   uint8_t _vaIndex;                      //!< Index to a first vararg or `kNoVarArgs`.
     487             :   uint8_t _ret;                          //!< TypeId of a return value.
     488             :   const uint8_t* _args;                  //!< TypeIds of function arguments.
     489             : };
     490             : 
     491             : // ============================================================================
     492             : // [asmjit::FuncSignatureT]
     493             : // ============================================================================
     494             : 
     495             : //! \internal
     496             : #define T(TYPE) TypeIdOf<TYPE>::kTypeId
     497             : namespace { // unnamed namespace to avoid unique global symbols
     498             : 
     499             : //! Static function signature (no arguments).
     500             : template<typename RET>
     501             : class FuncSignature0 : public FuncSignature {
     502             : public:
     503        1944 :   ASMJIT_INLINE FuncSignature0(uint32_t ccId = CallConv::kIdHost) noexcept {
     504             :     init(ccId, T(RET), nullptr, 0);
     505             :   }
     506             : };
     507             : 
     508             : //! Static function signature (1 argument).
     509             : template<typename RET, typename A0>
     510             : class FuncSignature1 : public FuncSignature {
     511             : public:
     512        1422 :   ASMJIT_INLINE FuncSignature1(uint32_t ccId = CallConv::kIdHost) noexcept {
     513             :     static const uint8_t args[] = { T(A0) };
     514             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     515             :   }
     516             : };
     517             : 
     518             : //! Static function signature (2 arguments).
     519             : template<typename RET, typename A0, typename A1>
     520             : class FuncSignature2 : public FuncSignature {
     521             : public:
     522         214 :   ASMJIT_INLINE FuncSignature2(uint32_t ccId = CallConv::kIdHost) noexcept {
     523             :     static const uint8_t args[] = { T(A0), T(A1) };
     524             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     525             :   }
     526             : };
     527             : 
     528             : //! Static function signature (3 arguments).
     529             : template<typename RET, typename A0, typename A1, typename A2>
     530             : class FuncSignature3 : public FuncSignature {
     531             : public:
     532             :   ASMJIT_INLINE FuncSignature3(uint32_t ccId = CallConv::kIdHost) noexcept {
     533             :     static const uint8_t args[] = { T(A0), T(A1), T(A2) };
     534             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     535             :   }
     536             : };
     537             : 
     538             : //! Static function signature (4 arguments).
     539             : template<typename RET, typename A0, typename A1, typename A2, typename A3>
     540             : class FuncSignature4 : public FuncSignature {
     541             : public:
     542             :   ASMJIT_INLINE FuncSignature4(uint32_t ccId = CallConv::kIdHost) noexcept {
     543             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3) };
     544             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     545             :   }
     546             : };
     547             : 
     548             : //! Static function signature (5 arguments).
     549             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4>
     550             : class FuncSignature5 : public FuncSignature {
     551             : public:
     552             :   ASMJIT_INLINE FuncSignature5(uint32_t ccId = CallConv::kIdHost) noexcept {
     553             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4) };
     554             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     555             :   }
     556             : };
     557             : 
     558             : //! Static function signature (6 arguments).
     559             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
     560             : class FuncSignature6 : public FuncSignature {
     561             : public:
     562             :   ASMJIT_INLINE FuncSignature6(uint32_t ccId = CallConv::kIdHost) noexcept {
     563             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5) };
     564             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     565             :   }
     566             : };
     567             : 
     568             : //! Static function signature (7 arguments).
     569             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
     570             : class FuncSignature7 : public FuncSignature {
     571             : public:
     572             :   ASMJIT_INLINE FuncSignature7(uint32_t ccId = CallConv::kIdHost) noexcept {
     573             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6) };
     574             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     575             :   }
     576             : };
     577             : 
     578             : //! Static function signature (8 arguments).
     579             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
     580             : class FuncSignature8 : public FuncSignature {
     581             : public:
     582             :   ASMJIT_INLINE FuncSignature8(uint32_t ccId = CallConv::kIdHost) noexcept {
     583             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7) };
     584             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     585             :   }
     586             : };
     587             : 
     588             : //! Static function signature (9 arguments).
     589             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
     590             : class FuncSignature9 : public FuncSignature {
     591             : public:
     592             :   ASMJIT_INLINE FuncSignature9(uint32_t ccId = CallConv::kIdHost) noexcept {
     593             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8) };
     594             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     595             :   }
     596             : };
     597             : 
     598             : //! Static function signature (10 arguments).
     599             : template<typename RET, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
     600             : class FuncSignature10 : public FuncSignature {
     601             : public:
     602             :   ASMJIT_INLINE FuncSignature10(uint32_t ccId = CallConv::kIdHost) noexcept {
     603             :     static const uint8_t args[] = { T(A0), T(A1), T(A2), T(A3), T(A4), T(A5), T(A6), T(A7), T(A8), T(A9) };
     604             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     605             :   }
     606             : };
     607             : 
     608             : #if ASMJIT_CC_HAS_VARIADIC_TEMPLATES
     609             : //! Static function signature (variadic).
     610             : template<typename RET, typename... ARGS>
     611             : class FuncSignatureT : public FuncSignature {
     612             : public:
     613             :   ASMJIT_INLINE FuncSignatureT(uint32_t ccId = CallConv::kIdHost) noexcept {
     614             :     static const uint8_t args[] = { (T(ARGS))... };
     615             :     init(ccId, T(RET), args, ASMJIT_ARRAY_SIZE(args));
     616             :   }
     617             : };
     618             : #endif // ASMJIT_CC_HAS_VARIADIC_TEMPLATES
     619             : 
     620             : }
     621             : #undef T
     622             : 
     623             : // ============================================================================
     624             : // [asmjit::FuncSignatureX]
     625             : // ============================================================================
     626             : 
     627             : //! Dynamic function signature.
     628             : class FuncSignatureX : public FuncSignature {
     629             : public:
     630             :   // --------------------------------------------------------------------------
     631             :   // [Construction / Destruction]
     632             :   // --------------------------------------------------------------------------
     633             : 
     634             :   ASMJIT_INLINE FuncSignatureX(uint32_t ccId = CallConv::kIdHost) noexcept {
     635             :     init(ccId, TypeId::kVoid, _builderArgList, 0);
     636             :   }
     637             : 
     638             :   // --------------------------------------------------------------------------
     639             :   // [Accessors]
     640             :   // --------------------------------------------------------------------------
     641             : 
     642             :   ASMJIT_INLINE void setCallConv(uint32_t ccId) noexcept {
     643             :     ASMJIT_ASSERT(ccId <= 0xFF);
     644             :     _callConv = static_cast<uint8_t>(ccId);
     645             :   }
     646             : 
     647             :   //! Set the return type to `retType`.
     648             :   ASMJIT_INLINE void setRet(uint32_t retType) noexcept { _ret = retType; }
     649             :   //! Set the return type based on `T`.
     650             :   template<typename T>
     651             :   ASMJIT_INLINE void setRetT() noexcept { setRet(TypeIdOf<T>::kTypeId); }
     652             : 
     653             :   //! Set the argument at index `i` to the `type`
     654             :   ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) noexcept {
     655             :     ASMJIT_ASSERT(i < _argCount);
     656             :     _builderArgList[i] = type;
     657             :   }
     658             :   //! Set the argument at index `i` to the type based on `T`.
     659             :   template<typename T>
     660             :   ASMJIT_INLINE void setArgT(uint32_t i) noexcept { setArg(i, TypeIdOf<T>::kTypeId); }
     661             : 
     662             :   //! Append an argument of `type` to the function prototype.
     663             :   ASMJIT_INLINE void addArg(uint32_t type) noexcept {
     664             :     ASMJIT_ASSERT(_argCount < kFuncArgCount);
     665             :     _builderArgList[_argCount++] = static_cast<uint8_t>(type);
     666             :   }
     667             :   //! Append an argument of type based on `T` to the function prototype.
     668             :   template<typename T>
     669             :   ASMJIT_INLINE void addArgT() noexcept { addArg(TypeIdOf<T>::kTypeId); }
     670             : 
     671             :   // --------------------------------------------------------------------------
     672             :   // [Members]
     673             :   // --------------------------------------------------------------------------
     674             : 
     675             :   uint8_t _builderArgList[kFuncArgCount];
     676             : };
     677             : 
     678             : // ============================================================================
     679             : // [asmjit::FuncDetail]
     680             : // ============================================================================
     681             : 
     682             : //! Function detail - CallConv and expanded FuncSignature.
     683             : //!
     684             : //! Function details is architecture and OS dependent representation of function.
     685             : //! It contains calling convention and expanded function signature so all
     686             : //! arguments have assigned either register type & id or stack address.
     687             : class FuncDetail {
     688             : public:
     689             :   ASMJIT_ENUM(Limits) {
     690             :     kMaxVRegKinds = Globals::kMaxVRegKinds
     691             :   };
     692             : 
     693             :   //! Argument or return value as defined by `FuncSignature`, but with register
     694             :   //! or stack address (and other metadata) assigned.
     695             :   struct Value {
     696             :     ASMJIT_ENUM(Parts) {
     697             :       kTypeIdShift      = 24,
     698             :       kTypeIdMask       = 0xFF000000U,
     699             : 
     700             :       kRegTypeShift     = 8,
     701             :       kRegTypeMask      = 0x0000FF00U,
     702             : 
     703             :       kRegIdShift       = 0,
     704             :       kRegIdMask        = 0x000000FFU,
     705             : 
     706             :       kStackOffsetShift = 0,
     707             :       kStackOffsetMask  = 0x0000FFFFU,
     708             : 
     709             :       kIsByReg          = 0x00010000U,
     710             :       kIsByStack        = 0x00020000U,
     711             :       kIsIndirect       = 0x00040000U
     712             :     };
     713             : 
     714             :     //! Get if this value is initialized (i.e. contains a valid data).
     715             :     ASMJIT_INLINE bool isInitialized() const noexcept { return _value != 0; }
     716             :     //! Initialize this in/out by a given `typeId`.
     717        5430 :     ASMJIT_INLINE void initTypeId(uint32_t typeId) noexcept { _value = typeId << kTypeIdShift; }
     718             :     //! Initialize this in/out by a given `typeId`, `regType`, and `regId`.
     719             :     ASMJIT_INLINE void initReg(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept {
     720        1446 :       _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg;
     721           0 :     }
     722             :     //! Initialize this in/out by a given `typeId` and `offset`.
     723             :     ASMJIT_INLINE void initStack(uint32_t typeId, uint32_t stackOffset) noexcept {
     724             :       _value = (typeId << kTypeIdShift) | (stackOffset << kStackOffsetShift) | kIsByStack;
     725             :     }
     726             :     //! Reset the value to its uninitialized and unassigned state.
     727             :     ASMJIT_INLINE void reset() noexcept { _value = 0; }
     728             : 
     729             :     ASMJIT_INLINE void assignToReg(uint32_t regType, uint32_t regId) noexcept {
     730             :       ASMJIT_ASSERT(!isAssigned());
     731         404 :       _value |= (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg;
     732        3580 :     }
     733             : 
     734             :     ASMJIT_INLINE void assignToStack(int32_t offset) noexcept {
     735             :       ASMJIT_ASSERT(!isAssigned());
     736           0 :       _value |= (offset << kStackOffsetShift) | kIsByStack;
     737             :     }
     738             : 
     739             :     //! Get if this argument is passed by register.
     740        6354 :     ASMJIT_INLINE bool byReg() const noexcept { return (_value & kIsByReg) != 0; }
     741             :     //! Get if this argument is passed by stack.
     742           0 :     ASMJIT_INLINE bool byStack() const noexcept { return (_value & kIsByStack) != 0; }
     743             :     //! Get if this argument is passed by register.
     744           0 :     ASMJIT_INLINE bool isAssigned() const noexcept { return (_value & (kIsByReg | kIsByStack)) != 0; }
     745             :     //! Get if this argument is passed through a pointer (used by WIN64 to pass XMM|YMM|ZMM).
     746             :     ASMJIT_INLINE bool isIndirect() const noexcept { return (_value & kIsIndirect) != 0; }
     747             : 
     748             :     //! Get virtual type of this argument or return value.
     749        5834 :     ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; }
     750             :     //! Get a register type of the register used to pass the argument or return the value.
     751        6662 :     ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; }
     752             :     //! Get a physical id of the register used to pass the argument or return the value.
     753        7066 :     ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; }
     754             :     //! Get a stack offset of this argument (always positive).
     755           0 :     ASMJIT_INLINE int32_t getStackOffset() const noexcept { return (_value & kStackOffsetMask) >> kStackOffsetShift; }
     756             : 
     757             :     uint32_t _value;
     758             :   };
     759             : 
     760             :   // --------------------------------------------------------------------------
     761             :   // [Construction / Destruction]
     762             :   // --------------------------------------------------------------------------
     763             : 
     764        3580 :   ASMJIT_INLINE FuncDetail() noexcept { reset(); }
     765             :   ASMJIT_INLINE FuncDetail(const FuncDetail& other) noexcept {
     766             :     ::memcpy(this, &other, sizeof(*this));
     767             :   }
     768             : 
     769             :   // --------------------------------------------------------------------------
     770             :   // [Init / Reset]
     771             :   // --------------------------------------------------------------------------
     772             : 
     773             :   //! Initialize this `FuncDetail` to the given signature.
     774             :   ASMJIT_API Error init(const FuncSignature& sign);
     775             :   ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
     776             : 
     777             :   // --------------------------------------------------------------------------
     778             :   // [Accessors - Calling Convention]
     779             :   // --------------------------------------------------------------------------
     780             : 
     781             :   //! Get the function's calling convention, see `CallConv`.
     782             :   ASMJIT_INLINE const CallConv& getCallConv() const noexcept { return _callConv; }
     783             : 
     784             :   //! Get CallConv flags, see \ref CallConv::Flags.
     785             :   ASMJIT_INLINE uint32_t getFlags() const noexcept { return _callConv.getFlags(); }
     786             :   //! Check if a CallConv `flag` is set, see \ref CallConv::Flags.
     787             :   ASMJIT_INLINE bool hasFlag(uint32_t ccFlag) const noexcept { return _callConv.hasFlag(ccFlag); }
     788             : 
     789             :   // --------------------------------------------------------------------------
     790             :   // [Accessors - Arguments and Return]
     791             :   // --------------------------------------------------------------------------
     792             : 
     793             :   //! Get count of function return values.
     794        3580 :   ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; }
     795             :   //! Get the number of function arguments.
     796       12590 :   ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; }
     797             : 
     798             :   //! Get whether the function has a return value.
     799        1944 :   ASMJIT_INLINE bool hasRet() const noexcept { return _retCount != 0; }
     800             :   //! Get function return value.
     801             :   ASMJIT_INLINE Value& getRet(size_t index = 0) noexcept {
     802             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets));
     803             :     return _rets[index];
     804             :   }
     805             :   //! Get function return value (const).
     806             :   ASMJIT_INLINE const Value& getRet(size_t index = 0) const noexcept {
     807             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_rets));
     808           0 :     return _rets[index];
     809             :   }
     810             : 
     811             :   //! Get function arguments array.
     812             :   ASMJIT_INLINE Value* getArgs() noexcept { return _args; }
     813             :   //! Get function arguments array (const).
     814             :   ASMJIT_INLINE const Value* getArgs() const noexcept { return _args; }
     815             : 
     816             :   ASMJIT_INLINE bool hasArg(size_t index) const noexcept {
     817             :     ASMJIT_ASSERT(index < kFuncArgCountLoHi);
     818             :     return _args[index].isInitialized();
     819             :   }
     820             : 
     821             :   //! Get function argument at index `index`.
     822             :   ASMJIT_INLINE Value& getArg(size_t index) noexcept {
     823             :     ASMJIT_ASSERT(index < kFuncArgCountLoHi);
     824             :     return _args[index];
     825             :   }
     826             : 
     827             :   //! Get function argument at index `index`.
     828             :   ASMJIT_INLINE const Value& getArg(size_t index) const noexcept {
     829             :     ASMJIT_ASSERT(index < kFuncArgCountLoHi);
     830           0 :     return _args[index];
     831             :   }
     832             : 
     833             :   ASMJIT_INLINE void resetArg(size_t index) noexcept {
     834             :     ASMJIT_ASSERT(index < kFuncArgCountLoHi);
     835             :     _args[index].reset();
     836             :   }
     837             : 
     838             :   //! Get if the function passes one or more argument by stack.
     839             :   ASMJIT_INLINE bool hasStackArgs() const noexcept { return _argStackSize != 0; }
     840             :   //! Get stack size needed for function arguments passed on the stack.
     841           0 :   ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; }
     842             : 
     843             :   ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _callConv.getNaturalStackAlignment(); }
     844             :   ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _callConv.getSpillZoneSize(); }
     845             :   ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _callConv.getRedZoneSize(); }
     846             : 
     847             :   ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { return _callConv.getPassedRegs(kind); }
     848             :   ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { return _callConv.getPreservedRegs(kind); }
     849             : 
     850             :   ASMJIT_INLINE uint32_t getUsedRegs(uint32_t kind) const noexcept {
     851             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     852        5216 :     return _usedRegs[kind];
     853             :   }
     854             : 
     855             :   ASMJIT_INLINE void addUsedRegs(uint32_t kind, uint32_t regs) noexcept {
     856             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     857        1850 :     _usedRegs[kind] |= regs;
     858           0 :   }
     859             : 
     860             :   // --------------------------------------------------------------------------
     861             :   // [Members]
     862             :   // --------------------------------------------------------------------------
     863             : 
     864             :   CallConv _callConv;                    //!< Calling convention.
     865             :   uint8_t _argCount;                     //!< Number of function arguments.
     866             :   uint8_t _retCount;                     //!< Number of function return values.
     867             :   uint32_t _usedRegs[kMaxVRegKinds];     //!< Registers that contains arguments (signature dependent).
     868             :   uint32_t _argStackSize;                //!< Size of arguments passed by stack.
     869             :   Value _rets[2];                        //!< Function return values.
     870             :   Value _args[kFuncArgCountLoHi];        //!< Function arguments.
     871             : };
     872             : 
     873             : // ============================================================================
     874             : // [asmjit::FuncFrameInfo]
     875             : // ============================================================================
     876             : 
     877             : //! Function-frame information.
     878             : //!
     879             : //! This structure can be used to create a function frame in a cross-platform
     880             : //! way. It contains information about the function's stack to be used and
     881             : //! registers to be saved and restored. Based on this information in can
     882             : //! calculate the optimal layout of a function as \ref FuncFrameLayout.
     883             : struct FuncFrameInfo {
     884             :   ASMJIT_ENUM(Limits) {
     885             :     kMaxVRegKinds = Globals::kMaxVRegKinds
     886             :   };
     887             : 
     888             :   //! Attributes.
     889             :   //!
     890             :   //! Attributes are designed in a way that all are initially false, and user
     891             :   //! or function-frame finalizer sets them when necessary. Architecture-specific
     892             :   //! attributes are prefixed with the architecture name.
     893             :   ASMJIT_ENUM(Attributes) {
     894             :     kAttrPreserveFP       = 0x00000001U, //!< Preserve frame pointer (EBP|RBP).
     895             :     kAttrCompactPE        = 0x00000002U, //!< Use smaller, but possibly slower prolog/epilog.
     896             :     kAttrHasCalls         = 0x00000004U, //!< Function calls other functions (is not leaf).
     897             : 
     898             :     kX86AttrAlignedVecSR  = 0x00010000U, //!< Use aligned save/restore of VEC regs.
     899             :     kX86AttrMmxCleanup    = 0x00020000U, //!< Emit EMMS instruction in epilog (X86).
     900             :     kX86AttrAvxCleanup    = 0x00040000U, //!< Emit VZEROUPPER instruction in epilog (X86).
     901             :     kX86AttrAvxEnabled    = 0x00080000U  //!< Use AVX instead of SSE for all operations (X86).
     902             :   };
     903             : 
     904             :   // --------------------------------------------------------------------------
     905             :   // [Construction / Destruction]
     906             :   // --------------------------------------------------------------------------
     907             : 
     908        1944 :   ASMJIT_INLINE FuncFrameInfo() noexcept { reset(); }
     909             : 
     910             :   ASMJIT_INLINE FuncFrameInfo(const FuncFrameInfo& other) noexcept {
     911             :     ::memcpy(this, &other, sizeof(*this));
     912             :   }
     913             : 
     914             :   // --------------------------------------------------------------------------
     915             :   // [Init / Reset]
     916             :   // --------------------------------------------------------------------------
     917             : 
     918             :   ASMJIT_INLINE void reset() noexcept {
     919             :     ::memset(this, 0, sizeof(*this));
     920        1944 :     _stackArgsRegId = Globals::kInvalidRegId;
     921             :   }
     922             : 
     923             :   // --------------------------------------------------------------------------
     924             :   // [Accessors]
     925             :   // --------------------------------------------------------------------------
     926             : 
     927             :   //! Get frame-info flags, see \ref Attributes.
     928             :   ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _attributes; }
     929             :   //! Check if a frame-info `flag` is set, see \ref Attributes.
     930             :   ASMJIT_INLINE bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; }
     931             :   //! Add `flags` to the frame-info, see \ref Attributes.
     932             :   ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _attributes |= attrs; }
     933             :   //! Clear `flags` from the frame-info, see \ref Attributes.
     934             :   ASMJIT_INLINE void clearAttributes(uint32_t attrs) noexcept { _attributes &= ~attrs; }
     935             : 
     936             :   //! Get if the function preserves frame pointer (EBP|ESP on X86).
     937        5832 :   ASMJIT_INLINE bool hasPreservedFP() const noexcept { return (_attributes & kAttrPreserveFP) != 0; }
     938             :   //! Enable preserved frame pointer.
     939             :   ASMJIT_INLINE void enablePreservedFP() noexcept { _attributes |= kAttrPreserveFP; }
     940             :   //! Disable preserved frame pointer.
     941             :   ASMJIT_INLINE void disablePreservedFP() noexcept { _attributes &= ~kAttrPreserveFP; }
     942             : 
     943             :   //! Get if the function prolog and epilog should be compacted (as small as possible).
     944             :   ASMJIT_INLINE bool hasCompactPE() const noexcept { return (_attributes & kAttrCompactPE) != 0; }
     945             :   //! Enable compact prolog/epilog.
     946             :   ASMJIT_INLINE void enableCompactPE() noexcept { _attributes |= kAttrCompactPE; }
     947             :   //! Disable compact prolog/epilog.
     948             :   ASMJIT_INLINE void disableCompactPE() noexcept { _attributes &= ~kAttrCompactPE; }
     949             : 
     950             :   //! Get if the function calls other functions.
     951        1012 :   ASMJIT_INLINE bool hasCalls() const noexcept { return (_attributes & kAttrHasCalls) != 0; }
     952             :   //! Set `kFlagHasCalls` to true.
     953        1636 :   ASMJIT_INLINE void enableCalls() noexcept { _attributes |= kAttrHasCalls; }
     954             :   //! Set `kFlagHasCalls` to false.
     955             :   ASMJIT_INLINE void disableCalls() noexcept { _attributes &= ~kAttrHasCalls; }
     956             : 
     957             :   //! Get if the function contains MMX cleanup - 'emms' instruction in epilog.
     958        1944 :   ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return (_attributes & kX86AttrMmxCleanup) != 0; }
     959             :   //! Enable MMX cleanup.
     960             :   ASMJIT_INLINE void enableMmxCleanup() noexcept { _attributes |= kX86AttrMmxCleanup; }
     961             :   //! Disable MMX cleanup.
     962             :   ASMJIT_INLINE void disableMmxCleanup() noexcept { _attributes &= ~kX86AttrMmxCleanup; }
     963             : 
     964             :   //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog.
     965        1944 :   ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return (_attributes & kX86AttrAvxCleanup) != 0; }
     966             :   //! Enable AVX cleanup.
     967             :   ASMJIT_INLINE void enableAvxCleanup() noexcept { _attributes |= kX86AttrAvxCleanup; }
     968             :   //! Disable AVX cleanup.
     969             :   ASMJIT_INLINE void disableAvxCleanup() noexcept { _attributes &= ~kX86AttrAvxCleanup; }
     970             : 
     971             :   //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog.
     972        1944 :   ASMJIT_INLINE bool isAvxEnabled() const noexcept { return (_attributes & kX86AttrAvxEnabled) != 0; }
     973             :   //! Enable AVX cleanup.
     974             :   ASMJIT_INLINE void enableAvx() noexcept { _attributes |= kX86AttrAvxEnabled; }
     975             :   //! Disable AVX cleanup.
     976             :   ASMJIT_INLINE void disableAvx() noexcept { _attributes &= ~kX86AttrAvxEnabled; }
     977             : 
     978             :   //! Get which registers (by `kind`) are saved/restored in prolog/epilog, respectively.
     979             :   ASMJIT_INLINE uint32_t getDirtyRegs(uint32_t kind) const noexcept {
     980             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     981        7776 :     return _dirtyRegs[kind];
     982             :   }
     983             : 
     984             :   //! Set which registers (by `kind`) are saved/restored in prolog/epilog, respectively.
     985             :   ASMJIT_INLINE void setDirtyRegs(uint32_t kind, uint32_t regs) noexcept {
     986             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     987        1944 :     _dirtyRegs[kind] = regs;
     988             :   }
     989             : 
     990             :   //! Add registers (by `kind`) to saved/restored registers.
     991             :   ASMJIT_INLINE void addDirtyRegs(uint32_t kind, uint32_t regs) noexcept {
     992             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
     993           0 :     _dirtyRegs[kind] |= regs;
     994           0 :   }
     995             : 
     996             :   ASMJIT_INLINE void setAllDirty() noexcept {
     997             :     _dirtyRegs[0] = 0xFFFFFFFFU;
     998             :     _dirtyRegs[1] = 0xFFFFFFFFU;
     999             :     _dirtyRegs[2] = 0xFFFFFFFFU;
    1000             :     _dirtyRegs[3] = 0xFFFFFFFFU;
    1001             :   }
    1002             : 
    1003             :   ASMJIT_INLINE void setAllDirty(uint32_t kind) noexcept {
    1004             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
    1005             :     _dirtyRegs[kind] = 0xFFFFFFFFU;
    1006             :   }
    1007             : 
    1008             :   //! Get stack-frame size used by the function.
    1009             :   ASMJIT_INLINE uint32_t getStackFrameSize() const noexcept { return _stackFrameSize; }
    1010             :   //! Get call-frame size used by the function.
    1011             :   ASMJIT_INLINE uint32_t getCallFrameSize() const noexcept { return _callFrameSize; }
    1012             : 
    1013             :   //! Get minimum stack-frame alignment required by the function.
    1014        1944 :   ASMJIT_INLINE uint32_t getStackFrameAlignment() const noexcept { return _stackFrameAlignment; }
    1015             :   //! Get minimum call-frame alignment required by the function.
    1016        1944 :   ASMJIT_INLINE uint32_t getCallFrameAlignment() const noexcept { return _callFrameAlignment; }
    1017             : 
    1018        1944 :   ASMJIT_INLINE void setStackFrameSize(uint32_t size) noexcept { _stackFrameSize = size; }
    1019             :   ASMJIT_INLINE void setCallFrameSize(uint32_t size) noexcept { _callFrameSize = size; }
    1020             : 
    1021             :   ASMJIT_INLINE void setStackFrameAlignment(uint32_t value) noexcept {
    1022             :     ASMJIT_ASSERT(value < 256);
    1023        1944 :     _stackFrameAlignment = static_cast<uint8_t>(value);
    1024             :   }
    1025             : 
    1026             :   ASMJIT_INLINE void setCallFrameAlignment(uint32_t value) noexcept {
    1027             :     ASMJIT_ASSERT(value < 256);
    1028             :     _callFrameAlignment = static_cast<uint8_t>(value);
    1029             :   }
    1030             : 
    1031             :   ASMJIT_INLINE void mergeStackFrameSize(uint32_t size) noexcept { _stackFrameSize = std::max<uint32_t>(_stackFrameSize, size); }
    1032        1636 :   ASMJIT_INLINE void mergeCallFrameSize(uint32_t size) noexcept { _callFrameSize = std::max<uint32_t>(_callFrameSize, size); }
    1033             : 
    1034             :   ASMJIT_INLINE void mergeStackFrameAlignment(uint32_t value) noexcept {
    1035             :     ASMJIT_ASSERT(value < 256);
    1036             :     _stackFrameAlignment = static_cast<uint8_t>(std::max<uint32_t>(_stackFrameAlignment, value));
    1037             :   }
    1038             : 
    1039             :   ASMJIT_INLINE void mergeCallFrameAlignment(uint32_t value) noexcept {
    1040             :     ASMJIT_ASSERT(value < 256);
    1041             :     _callFrameAlignment = static_cast<uint8_t>(std::max<uint32_t>(_callFrameAlignment, value));
    1042             :   }
    1043             : 
    1044             :   ASMJIT_INLINE bool hasStackArgsRegId() const noexcept {
    1045             :     return _stackArgsRegId != Globals::kInvalidRegId;
    1046             :   }
    1047        1944 :   ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; }
    1048        1944 :   ASMJIT_INLINE void setStackArgsRegId(uint32_t regId) { _stackArgsRegId = regId; }
    1049             : 
    1050             :   // --------------------------------------------------------------------------
    1051             :   // [Members]
    1052             :   // --------------------------------------------------------------------------
    1053             : 
    1054             :   uint32_t _attributes;                  //!< Function attributes.
    1055             :   uint32_t _dirtyRegs[kMaxVRegKinds];    //!< Registers used by the function.
    1056             : 
    1057             :   uint8_t _stackFrameAlignment;          //!< Minimum alignment of stack-frame.
    1058             :   uint8_t _callFrameAlignment;           //!< Minimum alignment of call-frame.
    1059             :   uint8_t _stackArgsRegId;               //!< Register that holds base-address to arguments passed by stack.
    1060             : 
    1061             :   uint32_t _stackFrameSize;              //!< Size of a stack-frame used by the function.
    1062             :   uint32_t _callFrameSize;               //!< Size of a call-frame (not part of _stackFrameSize).
    1063             : };
    1064             : 
    1065             : // ============================================================================
    1066             : // [asmjit::FuncFrameLayout]
    1067             : // ============================================================================
    1068             : 
    1069             : //! Function-frame layout.
    1070             : //!
    1071             : //! Function layout is used directly by prolog and epilog insertion helpers. It
    1072             : //! contains only information necessary to insert proper prolog and epilog, and
    1073             : //! should be always calculated from \ref FuncDetail and \ref FuncFrameInfo, where
    1074             : //! \ref FuncDetail defines function's calling convention and signature, and \ref
    1075             : //! FuncFrameInfo specifies how much stack is used, and which registers are dirty.
    1076             : struct FuncFrameLayout {
    1077             :   ASMJIT_ENUM(Limits) {
    1078             :     kMaxVRegKinds = Globals::kMaxVRegKinds
    1079             :   };
    1080             : 
    1081             :   // --------------------------------------------------------------------------
    1082             :   // [Init / Reset]
    1083             :   // --------------------------------------------------------------------------
    1084             : 
    1085             :   ASMJIT_API Error init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept;
    1086             :   ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
    1087             : 
    1088             :   // --------------------------------------------------------------------------
    1089             :   // [Accessors]
    1090             :   // --------------------------------------------------------------------------
    1091             : 
    1092        7776 :   ASMJIT_INLINE bool hasPreservedFP() const noexcept { return static_cast<bool>(_preservedFP); }
    1093           0 :   ASMJIT_INLINE bool hasDsaSlotUsed() const noexcept { return static_cast<bool>(_dsaSlotUsed); }
    1094           0 :   ASMJIT_INLINE bool hasAlignedVecSR() const noexcept { return static_cast<bool>(_alignedVecSR); }
    1095        5832 :   ASMJIT_INLINE bool hasDynamicAlignment() const noexcept { return static_cast<bool>(_dynamicAlignment); }
    1096             : 
    1097        1944 :   ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return static_cast<bool>(_mmxCleanup); }
    1098        1944 :   ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return static_cast<bool>(_avxCleanup); }
    1099           0 :   ASMJIT_INLINE bool isAvxEnabled() const noexcept { return static_cast<bool>(_avxEnabled); }
    1100             : 
    1101             :   ASMJIT_INLINE uint32_t getSavedRegs(uint32_t kind) const noexcept {
    1102             :     ASMJIT_ASSERT(kind < kMaxVRegKinds);
    1103        7776 :     return _savedRegs[kind];
    1104             :   }
    1105             : 
    1106             :   //! Get stack size.
    1107             :   ASMJIT_INLINE uint32_t getStackSize() const noexcept { return _stackSize; }
    1108             :   //! Get stack alignment.
    1109           0 :   ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; }
    1110             :   //! Get the offset needed to access the function's stack (it skips call-stack).
    1111             :   ASMJIT_INLINE uint32_t getStackBaseOffset() const noexcept { return _stackBaseOffset; }
    1112             : 
    1113             :   //! Get stack size required to save GP registers.
    1114           0 :   ASMJIT_INLINE uint32_t getGpStackSize() const noexcept { return _gpStackSize; }
    1115             :   //! Get stack size required to save VEC registers.
    1116             :   ASMJIT_INLINE uint32_t getVecStackSize() const noexcept { return _vecStackSize; }
    1117             : 
    1118             :   ASMJIT_INLINE uint32_t getGpStackOffset() const noexcept { return _gpStackOffset; }
    1119           0 :   ASMJIT_INLINE uint32_t getVecStackOffset() const noexcept { return _vecStackOffset; }
    1120             : 
    1121        1944 :   ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; }
    1122           0 :   ASMJIT_INLINE uint32_t getStackArgsOffset() const noexcept { return _stackArgsOffset; }
    1123             : 
    1124        3888 :   ASMJIT_INLINE bool hasStackAdjustment() const noexcept { return _stackAdjustment != 0; }
    1125             :   ASMJIT_INLINE uint32_t getStackAdjustment() const noexcept { return _stackAdjustment; }
    1126             : 
    1127        1944 :   ASMJIT_INLINE bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; }
    1128             :   ASMJIT_INLINE uint32_t getCalleeStackCleanup() const noexcept { return _calleeStackCleanup; }
    1129             : 
    1130             :   // --------------------------------------------------------------------------
    1131             :   // [Members]
    1132             :   // --------------------------------------------------------------------------
    1133             : 
    1134             :   uint8_t _stackAlignment;               //!< Final stack alignment of the functions.
    1135             :   uint8_t _stackBaseRegId;               //!< GP register that holds address of base stack address.
    1136             :   uint8_t _stackArgsRegId;               //!< GP register that holds address of the first argument passed by stack.
    1137             : 
    1138             :   uint32_t _savedRegs[kMaxVRegKinds];    //!< Registers that will be saved/restored in prolog/epilog.
    1139             : 
    1140             :   uint32_t _preservedFP : 1;             //!< Function preserves frame-pointer.
    1141             :   uint32_t _dsaSlotUsed : 1;             //!< True if `_dsaSlot` contains a valid memory slot/offset.
    1142             :   uint32_t _alignedVecSR : 1;            //!< Use instructions that perform aligned ops to save/restore XMM regs.
    1143             :   uint32_t _dynamicAlignment : 1;        //!< Function must dynamically align the stack.
    1144             : 
    1145             :   uint32_t _mmxCleanup : 1;              //!< Emit 'emms' in epilog (X86).
    1146             :   uint32_t _avxCleanup : 1;              //!< Emit 'vzeroupper' in epilog (X86).
    1147             :   uint32_t _avxEnabled : 1;              //!< Use AVX instead of SSE for SIMD saves/restores (X86).
    1148             : 
    1149             :   uint32_t _stackSize;                   //!< Stack size (sum of function's stack and call stack).
    1150             :   uint32_t _stackBaseOffset;             //!< Stack offset (non-zero if kFlagHasCalls is set).
    1151             :   uint32_t _stackAdjustment;             //!< Stack adjustment in prolog/epilog.
    1152             :   uint32_t _stackArgsOffset;             //!< Offset to the first argument passed by stack of _stackArgsRegId.
    1153             : 
    1154             :   uint32_t _dsaSlot;                     //!< Memory slot where the prolog inserter stores previous (unaligned) ESP.
    1155             :   uint16_t _calleeStackCleanup;          //!< How many bytes the callee should add to the stack (X86 STDCALL).
    1156             :   uint16_t _gpStackSize;                 //!< Stack size required to save GP regs.
    1157             :   uint16_t _vecStackSize;                //!< Stack size required to save VEC regs.
    1158             :   uint32_t _gpStackOffset;               //!< Offset where saved GP regs are stored.
    1159             :   uint32_t _vecStackOffset;              //!< Offset where saved GP regs are stored.
    1160             : };
    1161             : 
    1162             : // ============================================================================
    1163             : // [asmjit::FuncArgsMapper]
    1164             : // ============================================================================
    1165             : 
    1166             : //! Assign a physical register to each function argument.
    1167             : //!
    1168             : //! This is used to specify where each function argument should be shuffled
    1169             : //! or allocated (in case it's passed by stack).
    1170             : class FuncArgsMapper {
    1171             : public:
    1172             :   struct Value {
    1173             :     // NOTE: The layout is compatible with FuncDetail::Value except stack.
    1174             :     ASMJIT_ENUM(Parts) {
    1175             :       kTypeIdShift      = 24,
    1176             :       kTypeIdMask       = 0xFF000000U,
    1177             : 
    1178             :       kRegTypeShift     = 8,
    1179             :       kRegTypeMask      = 0x0000FF00U,
    1180             : 
    1181             :       kRegIdShift       = 0,
    1182             :       kRegIdMask        = 0x000000FFU,
    1183             : 
    1184             :       kIsAssigned       = 0x00010000U
    1185             :     };
    1186             : 
    1187             :     //! Get if this value is initialized (i.e. contains a valid data).
    1188           0 :     ASMJIT_INLINE bool isAssigned() const noexcept { return _value != 0; }
    1189             :     //! Initialize this in/out by a given `typeId`, `regType`, and `regId`.
    1190             :     ASMJIT_INLINE void assign(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept {
    1191             :       _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsAssigned;
    1192             :     }
    1193             :     //! Reset the value to its unassigned state.
    1194             :     ASMJIT_INLINE void reset() noexcept { _value = 0; }
    1195             : 
    1196             :     //! Get virtual type of this argument or return value.
    1197           0 :     ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _value >> kTypeIdShift; }
    1198             :     //! Get a register type of the register used to pass the argument or return the value.
    1199           0 :     ASMJIT_INLINE uint32_t getRegType() const noexcept { return (_value & kRegTypeMask) >> kRegTypeShift; }
    1200             :     //! Get a physical id of the register used to pass the argument or return the value.
    1201           0 :     ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; }
    1202             : 
    1203             :     uint32_t _value;
    1204             :   };
    1205             : 
    1206             :   // --------------------------------------------------------------------------
    1207             :   // [Construction / Destruction]
    1208             :   // --------------------------------------------------------------------------
    1209             : 
    1210             :   explicit ASMJIT_INLINE FuncArgsMapper(const FuncDetail* fd) noexcept { reset(fd); }
    1211             :   ASMJIT_INLINE FuncArgsMapper(const FuncArgsMapper& other) noexcept {
    1212             :     ::memcpy(this, &other, sizeof(*this));
    1213             :   }
    1214             : 
    1215             :   // --------------------------------------------------------------------------
    1216             :   // [Reset]
    1217             :   // --------------------------------------------------------------------------
    1218             : 
    1219             :   ASMJIT_INLINE void reset(const FuncDetail* fd = nullptr) noexcept {
    1220             :     _funcDetail = fd;
    1221             :     ::memset(_args, 0, sizeof(_args));
    1222             :   }
    1223             : 
    1224             :   // --------------------------------------------------------------------------
    1225             :   // [Accessors]
    1226             :   // --------------------------------------------------------------------------
    1227             : 
    1228           0 :   ASMJIT_INLINE const FuncDetail* getFuncDetail() const noexcept { return _funcDetail; }
    1229             :   ASMJIT_INLINE void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; }
    1230             : 
    1231             :   ASMJIT_INLINE Value& getArg(size_t index) noexcept {
    1232             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args));
    1233             :     return _args[index];
    1234             :   }
    1235             :   ASMJIT_INLINE const Value& getArg(size_t index) const noexcept {
    1236             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args));
    1237             :     return _args[index];
    1238             :   }
    1239             : 
    1240             :   ASMJIT_INLINE bool isAssigned(size_t index) const noexcept {
    1241             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args));
    1242             :     return _args[index].isAssigned();
    1243             :   }
    1244             : 
    1245             :   ASMJIT_INLINE void assign(size_t index, const Reg& reg, uint32_t typeId = TypeId::kVoid) noexcept {
    1246             :     // Not designed for virtual registers.
    1247             :     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args));
    1248             :     ASMJIT_ASSERT(reg.isPhysReg());
    1249             : 
    1250             :     _args[index].assign(typeId, reg.getType(), reg.getId());
    1251             :   }
    1252             : 
    1253             :   // NOTE: All `assignAll()` methods are shortcuts to assign all arguments at
    1254             :   // once, however, since registers are passed all at once these initializers
    1255             :   // don't provide any way to pass TypeId and/or to keep any argument between
    1256             :   // the arguments passed uninitialized.
    1257             :   ASMJIT_INLINE void assignAll(const Reg& a0) noexcept {
    1258             :     assign(0, a0);
    1259             :   }
    1260             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1) noexcept {
    1261             :     assign(0, a0); assign(1, a1);
    1262             :   }
    1263             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2) noexcept {
    1264             :     assign(0, a0); assign(1, a1); assign(2, a2);
    1265             :   }
    1266             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3) noexcept {
    1267             :     assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3);
    1268             :   }
    1269             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4) noexcept {
    1270             :     assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3);
    1271             :     assign(4, a4);
    1272             :   }
    1273             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5) noexcept {
    1274             :     assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3);
    1275             :     assign(4, a4); assign(5, a5);
    1276             :   }
    1277             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6) noexcept {
    1278             :     assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3);
    1279             :     assign(4, a4); assign(5, a5); assign(6, a6);
    1280             :   }
    1281             :   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1, const Reg& a2, const Reg& a3, const Reg& a4, const Reg& a5, const Reg& a6, const Reg& a7) noexcept {
    1282             :     assign(0, a0); assign(1, a1); assign(2, a2); assign(3, a3);
    1283             :     assign(4, a4); assign(5, a5); assign(6, a6); assign(7, a7);
    1284             :   }
    1285             : 
    1286             :   // --------------------------------------------------------------------------
    1287             :   // [Utilities]
    1288             :   // --------------------------------------------------------------------------
    1289             : 
    1290             :   //! Update `FuncFrameInfo` accordingly to FuncArgsMapper.
    1291             :   //!
    1292             :   //! This method must be called if you use `FuncArgsMapper` and you plan to
    1293             :   //! use `FuncUtils::allocArgs()` to remap all arguments after the prolog is
    1294             :   //! inserted.
    1295             :   ASMJIT_API Error updateFrameInfo(FuncFrameInfo& ffi) const noexcept;
    1296             : 
    1297             :   // --------------------------------------------------------------------------
    1298             :   // [Members]
    1299             :   // --------------------------------------------------------------------------
    1300             : 
    1301             :   const FuncDetail* _funcDetail;         //!< Function detail.
    1302             :   Value _args[kFuncArgCountLoHi];        //!< Mapping of each function argument.
    1303             : };
    1304             : 
    1305             : // ============================================================================
    1306             : // [asmjit::FuncUtils]
    1307             : // ============================================================================
    1308             : 
    1309             : struct FuncUtils {
    1310             :   ASMJIT_API static Error emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout);
    1311             :   ASMJIT_API static Error emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout);
    1312             :   ASMJIT_API static Error allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args);
    1313             : };
    1314             : 
    1315             : //! \}
    1316             : 
    1317             : } // asmjit namespace
    1318             : } // namespace PLMD
    1319             : 
    1320             : // [Api-End]
    1321             : #include "./asmjit_apiend.h"
    1322             : 
    1323             : // [Guard]
    1324             : #endif // _ASMJIT_BASE_FUNC_H
    1325             : #pragma GCC diagnostic pop
    1326             : #endif // __PLUMED_HAS_ASMJIT
    1327             : #endif

Generated by: LCOV version 1.15