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.
ASMJIT_ENUMCallConv69   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.
ASMJIT_ENUMCallConv222   ASMJIT_ENUM(Algorithm) {
223     kAlgorithmDefault    = 0,            //!< Default algorithm (cross-platform).
224     kAlgorithmWin64      = 1             //!< WIN64 specific algorithm.
225   };
226 
227   //! Calling convention flags.
ASMJIT_ENUMCallConv228   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.
ASMJIT_ENUMCallConv236   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 
isX86FamilyCallConv251   static ASMJIT_INLINE bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; }
isArmFamilyCallConv252   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 
resetCallConv260   ASMJIT_INLINE void reset() noexcept {
261     ::memset(this, 0, sizeof(*this));
262     ::memset(_passedOrder, 0xFF, sizeof(_passedOrder));
263   }
264 
265   // --------------------------------------------------------------------------
266   // [Accessors]
267   // --------------------------------------------------------------------------
268 
269   //! Get calling convention id, see \ref Id.
getIdCallConv270   ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
271   //! Set calling convention id, see \ref Id.
setIdCallConv272   ASMJIT_INLINE void setId(uint32_t id) noexcept { _id = static_cast<uint8_t>(id); }
273 
274   //! Get architecture type.
getArchTypeCallConv275   ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archType; }
276   //! Set architecture type.
setArchTypeCallConv277   ASMJIT_INLINE void setArchType(uint32_t archType) noexcept { _archType = static_cast<uint8_t>(archType); }
278 
279   //! Get calling convention algorithm, see \ref Algorithm.
getAlgorithmCallConv280   ASMJIT_INLINE uint32_t getAlgorithm() const noexcept { return _algorithm; }
281   //! Set calling convention algorithm, see \ref Algorithm.
setAlgorithmCallConv282   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.
hasFlagCallConv285   ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
286   //! Get calling convention flags, see \ref Flags.
getFlagsCallConv287   ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
288   //! Add calling convention flags, see \ref Flags.
setFlagsCallConv289   ASMJIT_INLINE void setFlags(uint32_t flag) noexcept { _flags = flag; };
290   //! Add calling convention flags, see \ref Flags.
addFlagsCallConv291   ASMJIT_INLINE void addFlags(uint32_t flag) noexcept { _flags |= flag; };
292 
293   //! Get a natural stack alignment.
getNaturalStackAlignmentCallConv294   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.
setNaturalStackAlignmentCallConv301   ASMJIT_INLINE void setNaturalStackAlignment(uint32_t value) noexcept {
302     ASMJIT_ASSERT(value < 256);
303     _naturalStackAlignment = static_cast<uint8_t>(value);
304   }
305 
306   //! Get if this calling convention specifies 'SpillZone'.
hasSpillZoneCallConv307   ASMJIT_INLINE bool hasSpillZone() const noexcept { return _spillZoneSize != 0; }
308   //! Get size of 'SpillZone'.
getSpillZoneSizeCallConv309   ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; }
310   //! Set size of 'SpillZone'.
setSpillZoneSizeCallConv311   ASMJIT_INLINE void setSpillZoneSize(uint32_t size) noexcept { _spillZoneSize = static_cast<uint8_t>(size); }
312 
313   //! Get if this calling convention specifies 'RedZone'.
hasRedZoneCallConv314   ASMJIT_INLINE bool hasRedZone() const noexcept { return _redZoneSize != 0; }
315   //! Get size of 'RedZone'.
getRedZoneSizeCallConv316   ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; }
317   //! Set size of 'RedZone'.
setRedZoneSizeCallConv318   ASMJIT_INLINE void setRedZoneSize(uint32_t size) noexcept { _redZoneSize = static_cast<uint16_t>(size); }
319 
getPassedOrderCallConv320   ASMJIT_INLINE const uint8_t* getPassedOrder(uint32_t kind) const noexcept {
321     ASMJIT_ASSERT(kind < kMaxVRegKinds);
322     return _passedOrder[kind].id;
323   }
324 
getPassedRegsCallConv325   ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept {
326     ASMJIT_ASSERT(kind < kMaxVRegKinds);
327     return _passedRegs[kind];
328   }
329 
_setPassedPackedCallConv330   ASMJIT_INLINE void _setPassedPacked(uint32_t kind, uint32_t p0, uint32_t p1) noexcept {
331     ASMJIT_ASSERT(kind < kMaxVRegKinds);
332 
333     _passedOrder[kind].packed[0] = p0;
334     _passedOrder[kind].packed[1] = p1;
335   }
336 
setPassedToNoneCallConv337   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     _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 
getPreservedRegsCallConv364   ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept {
365     ASMJIT_ASSERT(kind < kMaxVRegKinds);
366     return _preservedRegs[kind];
367   }
368 
369 
setPreservedRegsCallConv370   ASMJIT_INLINE void setPreservedRegs(uint32_t kind, uint32_t regs) noexcept {
371     ASMJIT_ASSERT(kind < kMaxVRegKinds);
372     _preservedRegs[kind] = regs;
373   }
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).
ASMJIT_ENUM(FuncArgIndex)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.
initFuncSignature438   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     _callConv = static_cast<uint8_t>(ccId);
443     _argCount = static_cast<uint8_t>(argCount);
444     _vaIndex = kNoVarArgs;
445     _ret = ret;
446     _args = args;
447   }
448 
resetFuncSignature449   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.
getCallConvFuncSignature458   ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; }
459 
460   //! Get if the function has variable number of arguments (...).
hasVarArgsFuncSignature461   ASMJIT_INLINE bool hasVarArgs() const noexcept { return _vaIndex != kNoVarArgs; }
462   //! Get the variable arguments (...) index, `kNoVarArgs` if none.
getVAIndexFuncSignature463   ASMJIT_INLINE uint32_t getVAIndex() const noexcept { return _vaIndex; }
464 
465   //! Get the number of function arguments.
getArgCountFuncSignature466   ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; }
467 
hasRetFuncSignature468   ASMJIT_INLINE bool hasRet() const noexcept { return _ret != TypeId::kVoid; }
469   //! Get the return value type.
getRetFuncSignature470   ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; }
471 
472   //! Get the type of the argument at index `i`.
getArgFuncSignature473   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.
getArgsFuncSignature478   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   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   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   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 
setCallConv(uint32_t ccId)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`.
setRet(uint32_t retType)648   ASMJIT_INLINE void setRet(uint32_t retType) noexcept { _ret = retType; }
649   //! Set the return type based on `T`.
650   template<typename T>
setRetT()651   ASMJIT_INLINE void setRetT() noexcept { setRet(TypeIdOf<T>::kTypeId); }
652 
653   //! Set the argument at index `i` to the `type`
setArg(uint32_t i,uint32_t 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>
setArgT(uint32_t i)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.
addArg(uint32_t type)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>
addArgT()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:
ASMJIT_ENUM(Limits)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 {
ASMJIT_ENUMValue696     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).
isInitializedValue715     ASMJIT_INLINE bool isInitialized() const noexcept { return _value != 0; }
716     //! Initialize this in/out by a given `typeId`.
initTypeIdValue717     ASMJIT_INLINE void initTypeId(uint32_t typeId) noexcept { _value = typeId << kTypeIdShift; }
718     //! Initialize this in/out by a given `typeId`, `regType`, and `regId`.
initRegValue719     ASMJIT_INLINE void initReg(uint32_t typeId, uint32_t regType, uint32_t regId) noexcept {
720       _value = (typeId << kTypeIdShift) | (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg;
721     }
722     //! Initialize this in/out by a given `typeId` and `offset`.
initStackValue723     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.
resetValue727     ASMJIT_INLINE void reset() noexcept { _value = 0; }
728 
assignToRegValue729     ASMJIT_INLINE void assignToReg(uint32_t regType, uint32_t regId) noexcept {
730       ASMJIT_ASSERT(!isAssigned());
731       _value |= (regType << kRegTypeShift) | (regId << kRegIdShift) | kIsByReg;
732     }
733 
assignToStackValue734     ASMJIT_INLINE void assignToStack(int32_t offset) noexcept {
735       ASMJIT_ASSERT(!isAssigned());
736       _value |= (offset << kStackOffsetShift) | kIsByStack;
737     }
738 
739     //! Get if this argument is passed by register.
byRegValue740     ASMJIT_INLINE bool byReg() const noexcept { return (_value & kIsByReg) != 0; }
741     //! Get if this argument is passed by stack.
byStackValue742     ASMJIT_INLINE bool byStack() const noexcept { return (_value & kIsByStack) != 0; }
743     //! Get if this argument is passed by register.
isAssignedValue744     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).
isIndirectValue746     ASMJIT_INLINE bool isIndirect() const noexcept { return (_value & kIsIndirect) != 0; }
747 
748     //! Get virtual type of this argument or return value.
getTypeIdValue749     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.
getRegTypeValue751     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.
getRegIdValue753     ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; }
754     //! Get a stack offset of this argument (always positive).
getStackOffsetValue755     ASMJIT_INLINE int32_t getStackOffset() const noexcept { return (_value & kStackOffsetMask) >> kStackOffsetShift; }
756 
757     uint32_t _value;
758   };
759 
760   // --------------------------------------------------------------------------
761   // [Construction / Destruction]
762   // --------------------------------------------------------------------------
763 
FuncDetail()764   ASMJIT_INLINE FuncDetail() noexcept { reset(); }
FuncDetail(const FuncDetail & other)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);
reset()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`.
getCallConv()782   ASMJIT_INLINE const CallConv& getCallConv() const noexcept { return _callConv; }
783 
784   //! Get CallConv flags, see \ref CallConv::Flags.
getFlags()785   ASMJIT_INLINE uint32_t getFlags() const noexcept { return _callConv.getFlags(); }
786   //! Check if a CallConv `flag` is set, see \ref CallConv::Flags.
hasFlag(uint32_t ccFlag)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.
getRetCount()794   ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; }
795   //! Get the number of function arguments.
getArgCount()796   ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _argCount; }
797 
798   //! Get whether the function has a return value.
hasRet()799   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     return _rets[index];
809   }
810 
811   //! Get function arguments array.
getArgs()812   ASMJIT_INLINE Value* getArgs() noexcept { return _args; }
813   //! Get function arguments array (const).
getArgs()814   ASMJIT_INLINE const Value* getArgs() const noexcept { return _args; }
815 
hasArg(size_t index)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`.
getArg(size_t 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`.
getArg(size_t index)828   ASMJIT_INLINE const Value& getArg(size_t index) const noexcept {
829     ASMJIT_ASSERT(index < kFuncArgCountLoHi);
830     return _args[index];
831   }
832 
resetArg(size_t index)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.
hasStackArgs()839   ASMJIT_INLINE bool hasStackArgs() const noexcept { return _argStackSize != 0; }
840   //! Get stack size needed for function arguments passed on the stack.
getArgStackSize()841   ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; }
842 
getNaturalStackAlignment()843   ASMJIT_INLINE uint32_t getNaturalStackAlignment() const noexcept { return _callConv.getNaturalStackAlignment(); }
getSpillZoneSize()844   ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _callConv.getSpillZoneSize(); }
getRedZoneSize()845   ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _callConv.getRedZoneSize(); }
846 
getPassedRegs(uint32_t kind)847   ASMJIT_INLINE uint32_t getPassedRegs(uint32_t kind) const noexcept { return _callConv.getPassedRegs(kind); }
getPreservedRegs(uint32_t kind)848   ASMJIT_INLINE uint32_t getPreservedRegs(uint32_t kind) const noexcept { return _callConv.getPreservedRegs(kind); }
849 
getUsedRegs(uint32_t kind)850   ASMJIT_INLINE uint32_t getUsedRegs(uint32_t kind) const noexcept {
851     ASMJIT_ASSERT(kind < kMaxVRegKinds);
852     return _usedRegs[kind];
853   }
854 
addUsedRegs(uint32_t kind,uint32_t regs)855   ASMJIT_INLINE void addUsedRegs(uint32_t kind, uint32_t regs) noexcept {
856     ASMJIT_ASSERT(kind < kMaxVRegKinds);
857     _usedRegs[kind] |= regs;
858   }
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 {
ASMJIT_ENUMFuncFrameInfo884   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.
ASMJIT_ENUMFuncFrameInfo893   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 
FuncFrameInfoFuncFrameInfo908   ASMJIT_INLINE FuncFrameInfo() noexcept { reset(); }
909 
FuncFrameInfoFuncFrameInfo910   ASMJIT_INLINE FuncFrameInfo(const FuncFrameInfo& other) noexcept {
911     ::memcpy(this, &other, sizeof(*this));
912   }
913 
914   // --------------------------------------------------------------------------
915   // [Init / Reset]
916   // --------------------------------------------------------------------------
917 
resetFuncFrameInfo918   ASMJIT_INLINE void reset() noexcept {
919     ::memset(this, 0, sizeof(*this));
920     _stackArgsRegId = Globals::kInvalidRegId;
921   }
922 
923   // --------------------------------------------------------------------------
924   // [Accessors]
925   // --------------------------------------------------------------------------
926 
927   //! Get frame-info flags, see \ref Attributes.
getAttributesFuncFrameInfo928   ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _attributes; }
929   //! Check if a frame-info `flag` is set, see \ref Attributes.
hasAttributeFuncFrameInfo930   ASMJIT_INLINE bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; }
931   //! Add `flags` to the frame-info, see \ref Attributes.
addAttributesFuncFrameInfo932   ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _attributes |= attrs; }
933   //! Clear `flags` from the frame-info, see \ref Attributes.
clearAttributesFuncFrameInfo934   ASMJIT_INLINE void clearAttributes(uint32_t attrs) noexcept { _attributes &= ~attrs; }
935 
936   //! Get if the function preserves frame pointer (EBP|ESP on X86).
hasPreservedFPFuncFrameInfo937   ASMJIT_INLINE bool hasPreservedFP() const noexcept { return (_attributes & kAttrPreserveFP) != 0; }
938   //! Enable preserved frame pointer.
enablePreservedFPFuncFrameInfo939   ASMJIT_INLINE void enablePreservedFP() noexcept { _attributes |= kAttrPreserveFP; }
940   //! Disable preserved frame pointer.
disablePreservedFPFuncFrameInfo941   ASMJIT_INLINE void disablePreservedFP() noexcept { _attributes &= ~kAttrPreserveFP; }
942 
943   //! Get if the function prolog and epilog should be compacted (as small as possible).
hasCompactPEFuncFrameInfo944   ASMJIT_INLINE bool hasCompactPE() const noexcept { return (_attributes & kAttrCompactPE) != 0; }
945   //! Enable compact prolog/epilog.
enableCompactPEFuncFrameInfo946   ASMJIT_INLINE void enableCompactPE() noexcept { _attributes |= kAttrCompactPE; }
947   //! Disable compact prolog/epilog.
disableCompactPEFuncFrameInfo948   ASMJIT_INLINE void disableCompactPE() noexcept { _attributes &= ~kAttrCompactPE; }
949 
950   //! Get if the function calls other functions.
hasCallsFuncFrameInfo951   ASMJIT_INLINE bool hasCalls() const noexcept { return (_attributes & kAttrHasCalls) != 0; }
952   //! Set `kFlagHasCalls` to true.
enableCallsFuncFrameInfo953   ASMJIT_INLINE void enableCalls() noexcept { _attributes |= kAttrHasCalls; }
954   //! Set `kFlagHasCalls` to false.
disableCallsFuncFrameInfo955   ASMJIT_INLINE void disableCalls() noexcept { _attributes &= ~kAttrHasCalls; }
956 
957   //! Get if the function contains MMX cleanup - 'emms' instruction in epilog.
hasMmxCleanupFuncFrameInfo958   ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return (_attributes & kX86AttrMmxCleanup) != 0; }
959   //! Enable MMX cleanup.
enableMmxCleanupFuncFrameInfo960   ASMJIT_INLINE void enableMmxCleanup() noexcept { _attributes |= kX86AttrMmxCleanup; }
961   //! Disable MMX cleanup.
disableMmxCleanupFuncFrameInfo962   ASMJIT_INLINE void disableMmxCleanup() noexcept { _attributes &= ~kX86AttrMmxCleanup; }
963 
964   //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog.
hasAvxCleanupFuncFrameInfo965   ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return (_attributes & kX86AttrAvxCleanup) != 0; }
966   //! Enable AVX cleanup.
enableAvxCleanupFuncFrameInfo967   ASMJIT_INLINE void enableAvxCleanup() noexcept { _attributes |= kX86AttrAvxCleanup; }
968   //! Disable AVX cleanup.
disableAvxCleanupFuncFrameInfo969   ASMJIT_INLINE void disableAvxCleanup() noexcept { _attributes &= ~kX86AttrAvxCleanup; }
970 
971   //! Get if the function contains AVX cleanup - 'vzeroupper' instruction in epilog.
isAvxEnabledFuncFrameInfo972   ASMJIT_INLINE bool isAvxEnabled() const noexcept { return (_attributes & kX86AttrAvxEnabled) != 0; }
973   //! Enable AVX cleanup.
enableAvxFuncFrameInfo974   ASMJIT_INLINE void enableAvx() noexcept { _attributes |= kX86AttrAvxEnabled; }
975   //! Disable AVX cleanup.
disableAvxFuncFrameInfo976   ASMJIT_INLINE void disableAvx() noexcept { _attributes &= ~kX86AttrAvxEnabled; }
977 
978   //! Get which registers (by `kind`) are saved/restored in prolog/epilog, respectively.
getDirtyRegsFuncFrameInfo979   ASMJIT_INLINE uint32_t getDirtyRegs(uint32_t kind) const noexcept {
980     ASMJIT_ASSERT(kind < kMaxVRegKinds);
981     return _dirtyRegs[kind];
982   }
983 
984   //! Set which registers (by `kind`) are saved/restored in prolog/epilog, respectively.
setDirtyRegsFuncFrameInfo985   ASMJIT_INLINE void setDirtyRegs(uint32_t kind, uint32_t regs) noexcept {
986     ASMJIT_ASSERT(kind < kMaxVRegKinds);
987     _dirtyRegs[kind] = regs;
988   }
989 
990   //! Add registers (by `kind`) to saved/restored registers.
addDirtyRegsFuncFrameInfo991   ASMJIT_INLINE void addDirtyRegs(uint32_t kind, uint32_t regs) noexcept {
992     ASMJIT_ASSERT(kind < kMaxVRegKinds);
993     _dirtyRegs[kind] |= regs;
994   }
995 
setAllDirtyFuncFrameInfo996   ASMJIT_INLINE void setAllDirty() noexcept {
997     _dirtyRegs[0] = 0xFFFFFFFFU;
998     _dirtyRegs[1] = 0xFFFFFFFFU;
999     _dirtyRegs[2] = 0xFFFFFFFFU;
1000     _dirtyRegs[3] = 0xFFFFFFFFU;
1001   }
1002 
setAllDirtyFuncFrameInfo1003   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.
getStackFrameSizeFuncFrameInfo1009   ASMJIT_INLINE uint32_t getStackFrameSize() const noexcept { return _stackFrameSize; }
1010   //! Get call-frame size used by the function.
getCallFrameSizeFuncFrameInfo1011   ASMJIT_INLINE uint32_t getCallFrameSize() const noexcept { return _callFrameSize; }
1012 
1013   //! Get minimum stack-frame alignment required by the function.
getStackFrameAlignmentFuncFrameInfo1014   ASMJIT_INLINE uint32_t getStackFrameAlignment() const noexcept { return _stackFrameAlignment; }
1015   //! Get minimum call-frame alignment required by the function.
getCallFrameAlignmentFuncFrameInfo1016   ASMJIT_INLINE uint32_t getCallFrameAlignment() const noexcept { return _callFrameAlignment; }
1017 
setStackFrameSizeFuncFrameInfo1018   ASMJIT_INLINE void setStackFrameSize(uint32_t size) noexcept { _stackFrameSize = size; }
setCallFrameSizeFuncFrameInfo1019   ASMJIT_INLINE void setCallFrameSize(uint32_t size) noexcept { _callFrameSize = size; }
1020 
setStackFrameAlignmentFuncFrameInfo1021   ASMJIT_INLINE void setStackFrameAlignment(uint32_t value) noexcept {
1022     ASMJIT_ASSERT(value < 256);
1023     _stackFrameAlignment = static_cast<uint8_t>(value);
1024   }
1025 
setCallFrameAlignmentFuncFrameInfo1026   ASMJIT_INLINE void setCallFrameAlignment(uint32_t value) noexcept {
1027     ASMJIT_ASSERT(value < 256);
1028     _callFrameAlignment = static_cast<uint8_t>(value);
1029   }
1030 
mergeStackFrameSizeFuncFrameInfo1031   ASMJIT_INLINE void mergeStackFrameSize(uint32_t size) noexcept { _stackFrameSize = std::max<uint32_t>(_stackFrameSize, size); }
mergeCallFrameSizeFuncFrameInfo1032   ASMJIT_INLINE void mergeCallFrameSize(uint32_t size) noexcept { _callFrameSize = std::max<uint32_t>(_callFrameSize, size); }
1033 
mergeStackFrameAlignmentFuncFrameInfo1034   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 
mergeCallFrameAlignmentFuncFrameInfo1039   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 
hasStackArgsRegIdFuncFrameInfo1044   ASMJIT_INLINE bool hasStackArgsRegId() const noexcept {
1045     return _stackArgsRegId != Globals::kInvalidRegId;
1046   }
getStackArgsRegIdFuncFrameInfo1047   ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; }
setStackArgsRegIdFuncFrameInfo1048   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 {
ASMJIT_ENUMFuncFrameLayout1077   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;
resetFuncFrameLayout1086   ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
1087 
1088   // --------------------------------------------------------------------------
1089   // [Accessors]
1090   // --------------------------------------------------------------------------
1091 
hasPreservedFPFuncFrameLayout1092   ASMJIT_INLINE bool hasPreservedFP() const noexcept { return static_cast<bool>(_preservedFP); }
hasDsaSlotUsedFuncFrameLayout1093   ASMJIT_INLINE bool hasDsaSlotUsed() const noexcept { return static_cast<bool>(_dsaSlotUsed); }
hasAlignedVecSRFuncFrameLayout1094   ASMJIT_INLINE bool hasAlignedVecSR() const noexcept { return static_cast<bool>(_alignedVecSR); }
hasDynamicAlignmentFuncFrameLayout1095   ASMJIT_INLINE bool hasDynamicAlignment() const noexcept { return static_cast<bool>(_dynamicAlignment); }
1096 
hasMmxCleanupFuncFrameLayout1097   ASMJIT_INLINE bool hasMmxCleanup() const noexcept { return static_cast<bool>(_mmxCleanup); }
hasAvxCleanupFuncFrameLayout1098   ASMJIT_INLINE bool hasAvxCleanup() const noexcept { return static_cast<bool>(_avxCleanup); }
isAvxEnabledFuncFrameLayout1099   ASMJIT_INLINE bool isAvxEnabled() const noexcept { return static_cast<bool>(_avxEnabled); }
1100 
getSavedRegsFuncFrameLayout1101   ASMJIT_INLINE uint32_t getSavedRegs(uint32_t kind) const noexcept {
1102     ASMJIT_ASSERT(kind < kMaxVRegKinds);
1103     return _savedRegs[kind];
1104   }
1105 
1106   //! Get stack size.
getStackSizeFuncFrameLayout1107   ASMJIT_INLINE uint32_t getStackSize() const noexcept { return _stackSize; }
1108   //! Get stack alignment.
getStackAlignmentFuncFrameLayout1109   ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; }
1110   //! Get the offset needed to access the function's stack (it skips call-stack).
getStackBaseOffsetFuncFrameLayout1111   ASMJIT_INLINE uint32_t getStackBaseOffset() const noexcept { return _stackBaseOffset; }
1112 
1113   //! Get stack size required to save GP registers.
getGpStackSizeFuncFrameLayout1114   ASMJIT_INLINE uint32_t getGpStackSize() const noexcept { return _gpStackSize; }
1115   //! Get stack size required to save VEC registers.
getVecStackSizeFuncFrameLayout1116   ASMJIT_INLINE uint32_t getVecStackSize() const noexcept { return _vecStackSize; }
1117 
getGpStackOffsetFuncFrameLayout1118   ASMJIT_INLINE uint32_t getGpStackOffset() const noexcept { return _gpStackOffset; }
getVecStackOffsetFuncFrameLayout1119   ASMJIT_INLINE uint32_t getVecStackOffset() const noexcept { return _vecStackOffset; }
1120 
getStackArgsRegIdFuncFrameLayout1121   ASMJIT_INLINE uint32_t getStackArgsRegId() const noexcept { return _stackArgsRegId; }
getStackArgsOffsetFuncFrameLayout1122   ASMJIT_INLINE uint32_t getStackArgsOffset() const noexcept { return _stackArgsOffset; }
1123 
hasStackAdjustmentFuncFrameLayout1124   ASMJIT_INLINE bool hasStackAdjustment() const noexcept { return _stackAdjustment != 0; }
getStackAdjustmentFuncFrameLayout1125   ASMJIT_INLINE uint32_t getStackAdjustment() const noexcept { return _stackAdjustment; }
1126 
hasCalleeStackCleanupFuncFrameLayout1127   ASMJIT_INLINE bool hasCalleeStackCleanup() const noexcept { return _calleeStackCleanup != 0; }
getCalleeStackCleanupFuncFrameLayout1128   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.
ASMJIT_ENUMValue1174     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).
isAssignedValue1188     ASMJIT_INLINE bool isAssigned() const noexcept { return _value != 0; }
1189     //! Initialize this in/out by a given `typeId`, `regType`, and `regId`.
assignValue1190     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.
resetValue1194     ASMJIT_INLINE void reset() noexcept { _value = 0; }
1195 
1196     //! Get virtual type of this argument or return value.
getTypeIdValue1197     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.
getRegTypeValue1199     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.
getRegIdValue1201     ASMJIT_INLINE uint32_t getRegId() const noexcept { return (_value & kRegIdMask) >> kRegIdShift; }
1202 
1203     uint32_t _value;
1204   };
1205 
1206   // --------------------------------------------------------------------------
1207   // [Construction / Destruction]
1208   // --------------------------------------------------------------------------
1209 
FuncArgsMapper(const FuncDetail * fd)1210   explicit ASMJIT_INLINE FuncArgsMapper(const FuncDetail* fd) noexcept { reset(fd); }
FuncArgsMapper(const FuncArgsMapper & other)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 
getFuncDetail()1228   ASMJIT_INLINE const FuncDetail* getFuncDetail() const noexcept { return _funcDetail; }
setFuncDetail(const FuncDetail * fd)1229   ASMJIT_INLINE void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; }
1230 
getArg(size_t index)1231   ASMJIT_INLINE Value& getArg(size_t index) noexcept {
1232     ASMJIT_ASSERT(index < ASMJIT_ARRAY_SIZE(_args));
1233     return _args[index];
1234   }
getArg(size_t index)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 
isAssigned(size_t index)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.
assignAll(const Reg & a0)1257   ASMJIT_INLINE void assignAll(const Reg& a0) noexcept {
1258     assign(0, a0);
1259   }
assignAll(const Reg & a0,const Reg & a1)1260   ASMJIT_INLINE void assignAll(const Reg& a0, const Reg& a1) noexcept {
1261     assign(0, a0); assign(1, a1);
1262   }
assignAll(const Reg & a0,const Reg & a1,const Reg & a2)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   }
assignAll(const Reg & a0,const Reg & a1,const Reg & a2,const Reg & a3)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   }
assignAll(const Reg & a0,const Reg & a1,const Reg & a2,const Reg & a3,const Reg & a4)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   }
assignAll(const Reg & a0,const Reg & a1,const Reg & a2,const Reg & a3,const Reg & a4,const Reg & a5)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   }
assignAll(const Reg & a0,const Reg & a1,const Reg & a2,const Reg & a3,const Reg & a4,const Reg & a5,const Reg & a6)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   }
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)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
1328