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