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