Function definitions.
Overview
AsmJit provides functionality that can be used to define function signatures and to calculate automatically optimal function frame that can be used directly by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler for a very long time, but was abstracted out and is now available for all users regardless of the emitter they use. The following use cases are possible:
- Calculate function frame before the function is generated - this is the only way available to BaseAssembler users and it will be described in this section.
- Calculate function frame after the function is generated - this way is generally used by BaseBuilder and BaseCompiler emitters and this way is generally described in Compiler section.
The following concepts are used to describe and create functions in AsmJit:
- TypeId - Type-id is an 8-bit value that describes a platform independent type as we know from C/C++. It provides abstractions for most common types like
int8_t
, uint32_t
, uintptr_t
, float
, double
, and all possible vector types to match ISAs up to AVX512. TypeId was introduced originally for Compiler, but it's now used by FuncSignature as well.
- CallConv - Describes a calling convention - this class contains instructions to assign registers and stack addresses to function arguments and return value(s), but doesn't specify any function signature itself. Calling conventions are architecture and OS dependent.
- FuncSignature - Describes a function signature, for example
int func(int, int)
. FuncSignature contains a function calling convention id, return value type, and function arguments. The signature itself is platform independent and uses TypeId to describe types of function arguments and function return value(s).
- FuncDetail - Architecture and ABI dependent information that describes CallConv and expanded FuncSignature. Each function argument and return value is represented as FuncValue that contains the original TypeId enriched with additional information that specifies whether the value is passed or returned by register (and which register) or by stack. Each value also contains some other metadata that provide additional information required to handle it properly (for example whether a vector is passed indirectly by a pointer as required by WIN64 calling convention).
- FuncFrame - Contains information about the function frame that can be used by prolog/epilog inserter (PEI). Holds call stack size size and alignment, local stack size and alignment, and various attributes that describe how prolog and epilog should be constructed.
FuncFrame
doesn't know anything about function's arguments or return values, it hold only information necessary to create a valid and ABI conforming function prologs and epilogs.
- FuncArgsAssignment - A helper class that can be used to reassign function arguments into user specified registers. It's architecture and ABI dependent mapping from function arguments described by CallConv and FuncDetail into registers specified by the user.
It's a lot of concepts where each represents one step in a function frame calculation. It can be used to create function prologs, epilogs, and also to calculate information necessary to perform function calls.
class CallConvId : uint8_tenumstrong◆
Calling convention id.
Calling conventions can be divided into the following groups:
- Universal - calling conventions are applicable to any target. They will be converted to a target dependent calling convention at runtime by CallConv::init() with some help from Environment. The purpose of these calling conventions is to make using functions less target dependent and closer to C and C++.
- Target specific - calling conventions that are used by a particular architecture and ABI. For example Windows 64-bit calling convention and AMD64 SystemV calling convention.
Constant | Description |
---|
kCDecl | Standard function call or explicit __cdecl where it can be specified.
This is a universal calling convention, which is used to initialize specific calling conventions based on architecture, platform, and its ABI.
|
kStdCall | __stdcall on targets that support this calling convention (X86).
- Note
- This calling convention is only supported on 32-bit X86. If used on environment that doesn't support this calling convention it will be replaced by CallConvId::kCDecl.
|
kFastCall | __fastcall on targets that support this calling convention (X86).
- Note
- This calling convention is only supported on 32-bit X86. If used on environment that doesn't support this calling convention it will be replaced by CallConvId::kCDecl.
|
kVectorCall | __vectorcall on targets that support this calling convention (X86/X64).
- Note
- This calling convention is only supported on 32-bit and 64-bit X86 architecture on Windows platform. If used on environment that doesn't support this calling it will be replaced by CallConvId::kCDecl.
|
kThisCall | __thiscall on targets that support this calling convention (X86).
- Note
- This calling convention is only supported on 32-bit X86 Windows platform. If used on environment that doesn't support this calling convention it will be replaced by CallConvId::kCDecl.
|
kRegParm1 | __attribute__((regparm(1))) convention (GCC and Clang).
|
kRegParm2 | __attribute__((regparm(2))) convention (GCC and Clang).
|
kRegParm3 | __attribute__((regparm(3))) convention (GCC and Clang).
|
kLightCall2 | AsmJit specific calling convention designed for calling functions inside a multimedia code that don't use many registers internally, but are long enough to be called and not inlined.
These functions are usually used to calculate trigonometric functions, logarithms, etc...
|
kSoftFloat | Soft-float calling convention (AArch32).
Floating point arguments are passed via general purpose registers.
|
kHardFloat | Hard-float calling convention (AArch32).
Floating point arguments are passed via SIMD registers.
|
kX64SystemV | X64 System-V calling convention.
|
kX64Windows | X64 Windows calling convention.
|
kMaxValue | Maximum value of CallConvId .
|
Strategy used by calling conventions to assign registers to function arguments.
Calling convention strategy describes how AsmJit should convert function arguments used by FuncSignature into register identifiers and stack offsets. The CallConvStrategy::kDefault strategy assigns registers and then stack whereas CallConvStrategy::kX64Windows strategy does register shadowing as defined by WIN64 calling convention, which is only used by 64-bit Windows.
Constant | Description |
---|
kDefault | Default register assignment strategy.
|
kX64Windows | Windows 64-bit ABI register assignment strategy.
|
kX64VectorCall | Windows 64-bit __vectorcall register assignment strategy.
|
kAArch64Apple | Apple's AArch64 calling convention (differs compared to AArch64 calling convention used by Linux).
|
kMaxValue | Maximum value of CallConvStrategy .
|
Calling convention flags.
Constant | Description |
---|
kNone | No flags.
|
kCalleePopsStack | Callee is responsible for cleaning up the stack.
|
kIndirectVecArgs | Pass vector arguments indirectly (as a pointer).
|
kPassFloatsByVec | Pass F32 and F64 arguments via VEC128 register.
|
kPassVecByStackIfVA | Pass MMX and vector arguments via stack if the function has variable arguments.
|
kPassMmxByGp | MMX registers are passed and returned via GP registers.
|
kPassMmxByXmm | MMX registers are passed and returned via XMM registers.
|
kVarArgCompatible | Calling convention can be used with variable arguments.
|
Attributes are designed in a way that all are initially false, and user or FuncFrame finalizer adds them when necessary.
Constant | Description |
---|
kNoAttributes | No attributes.
|
kHasVarArgs | Function has variable number of arguments.
|
kHasPreservedFP | Preserve frame pointer (don't omit FP).
|
kHasFuncCalls | Function calls other functions (is not leaf).
|
kAlignedVecSR | Function has aligned save/restore of vector registers.
|
kIndirectBranchProtection | Function must begin with an instruction that marks a start of a branch or function.
* `ENDBR32/ENDBR64` instruction is inserted at the beginning of the function (X86, X86_64).
* `BTI` instruction is inserted at the beginning of the function (AArch64)
|
kIsFinalized | FuncFrame is finalized and can be used by prolog/epilog inserter (PEI).
|
kX86_AVXEnabled | Enables the use of AVX within the function's body, prolog, and epilog (X86).
This flag instructs prolog and epilog emitter to use AVX instead of SSE for manipulating XMM registers.
|
kX86_AVX512Enabled | Enables the use of AVX-512 within the function's body, prolog, and epilog (X86).
This flag instructs Compiler register allocator to use additional 16 registers introduced by AVX-512. Additionally, if the functions saves full width of ZMM registers (custom calling conventions only) then the prolog/epilog inserter would use AVX-512 move instructions to emit the save and restore sequence.
|
kX86_MMXCleanup | This flag instructs the epilog writer to emit EMMS instruction before RET (X86).
|
kX86_AVXCleanup | This flag instructs the epilog writer to emit VZEROUPPER instruction before RET (X86).
|