summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/src/asmjit/x86/x86compiler.h
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/src/asmjit/x86/x86compiler.h')
-rw-r--r--3rdparty/asmjit/src/asmjit/x86/x86compiler.h579
1 files changed, 292 insertions, 287 deletions
diff --git a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h
index 4c64b3b6e40..b281e208879 100644
--- a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h
+++ b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project <https://asmjit.com>
//
-// * Official AsmJit Home Page: https://asmjit.com
-// * Official Github Repository: https://github.com/asmjit/asmjit
-//
-// Copyright (c) 2008-2020 The AsmJit Authors
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_X86_X86COMPILER_H_INCLUDED
#define ASMJIT_X86_X86COMPILER_H_INCLUDED
@@ -28,7 +10,6 @@
#ifndef ASMJIT_NO_COMPILER
#include "../core/compiler.h"
-#include "../core/datatypes.h"
#include "../core/type.h"
#include "../x86/x86emitter.h"
@@ -37,16 +18,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! \addtogroup asmjit_x86
//! \{
-// ============================================================================
-// [asmjit::x86::Compiler]
-// ============================================================================
-
//! X86/X64 compiler implementation.
//!
//! ### Compiler Basics
//!
-//! The first \ref x86::Compiler example shows how to generate a function that
-//! simply returns an integer value. It's an analogy to the first Assembler example:
+//! The first \ref x86::Compiler example shows how to generate a function that simply returns an integer value. It's
+//! an analogy to the first Assembler example:
//!
//! ```
//! #include <asmjit/x86.h>
@@ -58,41 +35,40 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! typedef int (*Func)(void);
//!
//! int main() {
-//! JitRuntime rt; // Runtime specialized for JIT code execution.
-//! CodeHolder code; // Holds code and relocation information.
+//! JitRuntime rt; // Runtime specialized for JIT code execution.
+//! CodeHolder code; // Holds code and relocation information.
//!
-//! code.init(rt.environment()); // Initialize code to match the JIT environment.
-//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
+//! code.init(rt.environment(), // Initialize code to match the JIT environment.
+//! rt.cpuFeatures());
+//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
//!
-//! cc.addFunc(FuncSignatureT<int>());// Begin a function of `int fn(void)` signature.
+//! cc.addFunc(FuncSignature::build<int>()); // Begin a function of `int fn(void)` signature.
//!
-//! x86::Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register.
-//! cc.mov(vReg, 1); // Move one to our virtual register `vReg`.
-//! cc.ret(vReg); // Return `vReg` from the function.
+//! x86::Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register.
+//! cc.mov(vReg, 1); // Move one to our virtual register `vReg`.
+//! cc.ret(vReg); // Return `vReg` from the function.
//!
-//! cc.endFunc(); // End of the function body.
-//! cc.finalize(); // Translate and assemble the whole 'cc' content.
+//! cc.endFunc(); // End of the function body.
+//! cc.finalize(); // Translate and assemble the whole 'cc' content.
//! // ----> x86::Compiler is no longer needed from here and can be destroyed <----
//!
//! Func fn;
-//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
-//! if (err) return 1; // Handle a possible error returned by AsmJit.
+//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
+//! if (err) return 1; // Handle a possible error returned by AsmJit.
//! // ----> CodeHolder is no longer needed from here and can be destroyed <----
//!
-//! int result = fn(); // Execute the generated code.
-//! printf("%d\n", result); // Print the resulting "1".
+//! int result = fn(); // Execute the generated code.
+//! printf("%d\n", result); // Print the resulting "1".
//!
-//! rt.release(fn); // Explicitly remove the function from the runtime.
+//! rt.release(fn); // Explicitly remove the function from the runtime.
//! return 0;
//! }
//! ```
//!
-//! The \ref BaseCompiler::addFunc() and \ref BaseCompiler::endFunc() functions
-//! are used to define the function and its end. Both must be called per function,
-//! but the body doesn't have to be generated in sequence. An example of generating
-//! two functions will be shown later. The next example shows more complicated code
-//! that contain a loop and generates a simple memory copy function that uses
-//! `uint32_t` items:
+//! The \ref BaseCompiler::addFunc() and \ref BaseCompiler::endFunc() functions are used to define the function and
+//! its end. Both must be called per function, but the body doesn't have to be generated in sequence. An example of
+//! generating two functions will be shown later. The next example shows more complicated code that contain a loop
+//! and generates a simple memory copy function that uses `uint32_t` items:
//!
//! ```
//! #include <asmjit/x86.h>
@@ -104,48 +80,49 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count);
//!
//! int main() {
-//! JitRuntime rt; // Runtime specialized for JIT code execution.
-//! CodeHolder code; // Holds code and relocation information.
+//! JitRuntime rt; // Runtime specialized for JIT code execution.
+//! CodeHolder code; // Holds code and relocation information.
//!
-//! code.init(rt.environment()); // Initialize code to match the JIT environment.
-//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
+//! code.init(rt.environment(), // Initialize code to match the JIT environment.
+//! rt.cpuFeatures());
+//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
//!
-//! cc.addFunc( // Begin the function of the following signature:
-//! FuncSignatureT<void, // Return value - void (no return value).
-//! uint32_t*, // 1st argument - uint32_t* (machine reg-size).
-//! const uint32_t*, // 2nd argument - uint32_t* (machine reg-size).
-//! size_t>()); // 3rd argument - size_t (machine reg-size).
+//! FuncNode* funcNode = cc.addFunc ( // Begin the function of the following signature:
+//! FuncSignature::build<void, // Return value - void (no return value).
+//! uint32_t*, // 1st argument - uint32_t* (machine reg-size).
+//! const uint32_t*, // 2nd argument - uint32_t* (machine reg-size).
+//! size_t>()); // 3rd argument - size_t (machine reg-size).
//!
-//! Label L_Loop = cc.newLabel(); // Start of the loop.
-//! Label L_Exit = cc.newLabel(); // Used to exit early.
+//! Label L_Loop = cc.newLabel(); // Start of the loop.
+//! Label L_Exit = cc.newLabel(); // Used to exit early.
//!
-//! x86::Gp dst = cc.newIntPtr("dst");// Create `dst` register (destination pointer).
-//! x86::Gp src = cc.newIntPtr("src");// Create `src` register (source pointer).
-//! x86::Gp i = cc.newUIntPtr("i"); // Create `i` register (loop counter).
+//! x86::Gp dst = cc.newIntPtr("dst"); // Create `dst` register (destination pointer).
+//! x86::Gp src = cc.newIntPtr("src"); // Create `src` register (source pointer).
+//! x86::Gp i = cc.newUIntPtr("i"); // Create `i` register (loop counter).
//!
-//! cc.setArg(0, dst); // Assign `dst` argument.
-//! cc.setArg(1, src); // Assign `src` argument.
-//! cc.setArg(2, i); // Assign `i` argument.
+//! funcNode->setArg(0, dst); // Assign `dst` argument.
+//! funcNode->setArg(1, src); // Assign `src` argument.
+//! funcNode->setArg(2, i); // Assign `i` argument.
//!
-//! cc.test(i, i); // Early exit if length is zero.
+//! cc.test(i, i); // Early exit if length is zero.
//! cc.jz(L_Exit);
//!
-//! cc.bind(L_Loop); // Bind the beginning of the loop here.
+//! cc.bind(L_Loop); // Bind the beginning of the loop here.
//!
-//! x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes).
-//! cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address.
-//! cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address.
+//! x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes).
+//! cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address.
+//! cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address.
//!
-//! cc.add(src, 4); // Increment `src`.
-//! cc.add(dst, 4); // Increment `dst`.
+//! cc.add(src, 4); // Increment `src`.
+//! cc.add(dst, 4); // Increment `dst`.
//!
-//! cc.dec(i); // Loop until `i` is non-zero.
+//! cc.dec(i); // Loop until `i` is non-zero.
//! cc.jnz(L_Loop);
//!
-//! cc.bind(L_Exit); // Label used by early exit.
-//! cc.endFunc(); // End of the function body.
+//! cc.bind(L_Exit); // Label used by early exit.
+//! cc.endFunc(); // End of the function body.
//!
-//! cc.finalize(); // Translate and assemble the whole 'cc' content.
+//! cc.finalize(); // Translate and assemble the whole 'cc' content.
//! // ----> x86::Compiler is no longer needed from here and can be destroyed <----
//!
//! // Add the generated code to the runtime.
@@ -170,11 +147,68 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! }
//! ```
//!
+//! ### AVX and AVX-512
+//!
+//! AVX and AVX-512 code generation must be explicitly enabled via \ref FuncFrame to work properly. If it's not setup
+//! correctly then Prolog & Epilog would use SSE instead of AVX instructions to work with SIMD registers. In addition,
+//! Compiler requires explicitly enable AVX-512 via \ref FuncFrame in order to use all 32 SIMD registers.
+//!
+//! ```
+//! #include <asmjit/x86.h>
+//! #include <stdio.h>
+//!
+//! using namespace asmjit;
+//!
+//! // Signature of the generated function.
+//! typedef void (*Func)(void*);
+//!
+//! int main() {
+//! JitRuntime rt; // Runtime specialized for JIT code execution.
+//! CodeHolder code; // Holds code and relocation information.
+//!
+//! code.init(rt.environment(), // Initialize code to match the JIT environment.
+//! rt.cpuFeatures());
+//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
+//!
+//! FuncNode* funcNode = cc.addFunc(FuncSignature::build<void, void*>());
+//!
+//! // Use the following to enable AVX and/or AVX-512.
+//! funcNode->frame().setAvxEnabled();
+//! funcNode->frame().setAvx512Enabled();
+//!
+//! // Do something with the input pointer.
+//! x86::Gp addr = cc.newIntPtr("addr");
+//! x86::Zmm vreg = cc.newZmm("vreg");
+//!
+//! funcNode->setArg(0, addr);
+//!
+//! cc.vmovdqu32(vreg, x86::ptr(addr));
+//! cc.vpaddq(vreg, vreg, vreg);
+//! cc.vmovdqu32(x86::ptr(addr), vreg);
+//!
+//! cc.endFunc(); // End of the function body.
+//! cc.finalize(); // Translate and assemble the whole 'cc' content.
+//! // ----> x86::Compiler is no longer needed from here and can be destroyed <----
+//!
+//! Func fn;
+//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime.
+//! if (err) return 1; // Handle a possible error returned by AsmJit.
+//! // ----> CodeHolder is no longer needed from here and can be destroyed <----
+//!
+//! // Execute the generated code and print some output.
+//! uint64_t data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+//! fn(data);
+//! printf("%llu\n", (unsigned long long)data[0]);
+//!
+//! rt.release(fn); // Explicitly remove the function from the runtime.
+//! return 0;
+//! }
+//! ```
+//!
//! ### Recursive Functions
//!
-//! It's possible to create more functions by using the same \ref x86::Compiler
-//! instance and make links between them. In such case it's important to keep
-//! the pointer to \ref FuncNode.
+//! It's possible to create more functions by using the same \ref x86::Compiler instance and make links between them.
+//! In such case it's important to keep the pointer to \ref FuncNode.
//!
//! The example below creates a simple Fibonacci function that calls itself recursively:
//!
@@ -188,47 +222,48 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! typedef uint32_t (*Fibonacci)(uint32_t x);
//!
//! int main() {
-//! JitRuntime rt; // Runtime specialized for JIT code execution.
-//! CodeHolder code; // Holds code and relocation information.
+//! JitRuntime rt; // Runtime specialized for JIT code execution.
+//! CodeHolder code; // Holds code and relocation information.
//!
-//! code.init(rt.environment()); // Initialize code to match the JIT environment.
-//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
+//! code.init(rt.environment(), // Initialize code to match the JIT environment.
+//! rt.cpuFeatures());
+//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
//!
-//! FuncNode* func = cc.addFunc( // Begin of the Fibonacci function, addFunc()
-//! FuncSignatureT<int, int>()); // Returns a pointer to the FuncNode node.
+//! FuncNode* funcNode = cc.addFunc( // Begin of the Fibonacci function, addFunc()
+//! FuncSignature::build<int, int>()); // Returns a pointer to the FuncNode node.
//!
-//! Label L_Exit = cc.newLabel() // Exit label.
-//! x86::Gp x = cc.newU32(); // Function x argument.
-//! x86::Gp y = cc.newU32(); // Temporary.
+//! Label L_Exit = cc.newLabel(); // Exit label.
+//! x86::Gp x = cc.newUInt32(); // Function x argument.
+//! x86::Gp y = cc.newUInt32(); // Temporary.
//!
-//! cc.setArg(0, x);
+//! funcNode->setArg(0, x);
//!
-//! cc.cmp(x, 3); // Return x if less than 3.
+//! cc.cmp(x, 3); // Return x if less than 3.
//! cc.jb(L_Exit);
//!
-//! cc.mov(y, x); // Make copy of the original x.
-//! cc.dec(x); // Decrease x.
+//! cc.mov(y, x); // Make copy of the original x.
+//! cc.dec(x); // Decrease x.
//!
-//! InvokeNode* invokeNode; // Function invocation:
-//! cc.invoke(&invokeNode, // - InvokeNode (output).
-//! func->label(), // - Function address or Label.
-//! FuncSignatureT<int, int>()); // - Function signature.
+//! InvokeNode* invokeNode; // Function invocation:
+//! cc.invoke(&invokeNode, // - InvokeNode (output).
+//! funcNode->label(), // - Function address or Label.
+//! FuncSignature::build<int, int>()); // - Function signature.
//!
-//! invokeNode->setArg(0, x); // Assign x as the first argument.
-//! invokeNode->setRet(0, x); // Assign x as a return value as well.
+//! invokeNode->setArg(0, x); // Assign x as the first argument.
+//! invokeNode->setRet(0, x); // Assign x as a return value as well.
//!
-//! cc.add(x, y); // Combine the return value with y.
+//! cc.add(x, y); // Combine the return value with y.
//!
//! cc.bind(L_Exit);
-//! cc.ret(x); // Return x.
-//! cc.endFunc(); // End of the function body.
+//! cc.ret(x); // Return x.
+//! cc.endFunc(); // End of the function body.
//!
-//! cc.finalize(); // Translate and assemble the whole 'cc' content.
+//! cc.finalize(); // Translate and assemble the whole 'cc' content.
//! // ----> x86::Compiler is no longer needed from here and can be destroyed <----
//!
//! Fibonacci fib;
-//! Error err = rt.add(&fib, &code); // Add the generated code to the runtime.
-//! if (err) return 1; // Handle a possible error returned by AsmJit.
+//! Error err = rt.add(&fib, &code); // Add the generated code to the runtime.
+//! if (err) return 1; // Handle a possible error returned by AsmJit.
//! // ----> CodeHolder is no longer needed from here and can be destroyed <----
//!
//! // Test the generated code.
@@ -241,7 +276,10 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//!
//! ### Stack Management
//!
-//! Function's stack-frame is managed automatically, which is used by the register allocator to spill virtual registers. It also provides an interface to allocate user-defined block of the stack, which can be used as a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values.
+//! Function's stack-frame is managed automatically, which is used by the register allocator to spill virtual
+//! registers. It also provides an interface to allocate user-defined block of the stack, which can be used as
+//! a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated,
+//! filled by bytes starting from 0 to 255 and then iterated again to sum all the values.
//!
//! ```
//! #include <asmjit/x86.h>
@@ -253,13 +291,14 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! typedef int (*Func)(void);
//!
//! int main() {
-//! JitRuntime rt; // Runtime specialized for JIT code execution.
-//! CodeHolder code; // Holds code and relocation information.
+//! JitRuntime rt; // Runtime specialized for JIT code execution.
+//! CodeHolder code; // Holds code and relocation information.
//!
-//! code.init(rt.environment()); // Initialize code to match the JIT environment.
-//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
+//! code.init(rt.environment(), // Initialize code to match the JIT environment.
+//! rt.cpuFeatures());
+//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code.
//!
-//! cc.addFunc(FuncSignatureT<int>());// Create a function that returns int.
+//! cc.addFunc(FuncSignature::build<int>()); // Create a function that returns int.
//!
//! x86::Gp p = cc.newIntPtr("p");
//! x86::Gp i = cc.newIntPtr("i");
@@ -267,9 +306,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! // Allocate 256 bytes on the stack aligned to 4 bytes.
//! x86::Mem stack = cc.newStack(256, 4);
//!
-//! x86::Mem stackIdx(stack); // Copy of stack with i added.
-//! stackIdx.setIndex(i); // stackIdx <- stack[i].
-//! stackIdx.setSize(1); // stackIdx <- byte ptr stack[i].
+//! x86::Mem stackIdx(stack); // Copy of stack with i added.
+//! stackIdx.setIndex(i); // stackIdx <- stack[i].
+//! stackIdx.setSize(1); // stackIdx <- byte ptr stack[i].
//!
//! // Load a stack address to `p`. This step is purely optional and shows
//! // that `lea` is useful to load a memory operands address (even absolute)
@@ -282,41 +321,41 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! Label L1 = cc.newLabel();
//! Label L2 = cc.newLabel();
//!
-//! cc.bind(L1); // First loop, fill the stack.
-//! cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i).
+//! cc.bind(L1); // First loop, fill the stack.
+//! cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i).
//!
-//! cc.inc(i); // i++;
-//! cc.cmp(i, 256); // if (i < 256)
-//! cc.jb(L1); // goto L1;
+//! cc.inc(i); // i++;
+//! cc.cmp(i, 256); // if (i < 256)
+//! cc.jb(L1); // goto L1;
//!
//! // Second loop, sum all bytes stored in `stack`.
-//! x86::Gp sum = cc.newI32("sum");
-//! x86::Gp val = cc.newI32("val");
+//! x86::Gp sum = cc.newInt32("sum");
+//! x86::Gp val = cc.newInt32("val");
//!
//! cc.xor_(i, i);
//! cc.xor_(sum, sum);
//!
//! cc.bind(L2);
//!
-//! cc.movzx(val, stackIdx); // val = uint32_t(stack[i]);
-//! cc.add(sum, val); // sum += val;
+//! cc.movzx(val, stackIdx); // val = uint32_t(stack[i]);
+//! cc.add(sum, val); // sum += val;
//!
-//! cc.inc(i); // i++;
-//! cc.cmp(i, 256); // if (i < 256)
-//! cc.jb(L2); // goto L2;
+//! cc.inc(i); // i++;
+//! cc.cmp(i, 256); // if (i < 256)
+//! cc.jb(L2); // goto L2;
//!
-//! cc.ret(sum); // Return the `sum` of all values.
-//! cc.endFunc(); // End of the function body.
+//! cc.ret(sum); // Return the `sum` of all values.
+//! cc.endFunc(); // End of the function body.
//!
-//! cc.finalize(); // Translate and assemble the whole 'cc' content.
+//! cc.finalize(); // Translate and assemble the whole 'cc' content.
//! // ----> x86::Compiler is no longer needed from here and can be destroyed <----
//!
//! Func func;
-//! Error err = rt.add(&func, &code); // Add the generated code to the runtime.
-//! if (err) return 1; // Handle a possible error returned by AsmJit.
+//! Error err = rt.add(&func, &code); // Add the generated code to the runtime.
+//! if (err) return 1; // Handle a possible error returned by AsmJit.
//! // ----> CodeHolder is no longer needed from here and can be destroyed <----
//!
-//! printf("Func() -> %d\n", func()); // Test the generated code.
+//! printf("Func() -> %d\n", func()); // Test the generated code.
//!
//! rt.release(func);
//! return 0;
@@ -327,12 +366,11 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//!
//! Compiler provides two constant pools for a general purpose code generation:
//!
-//! - Local constant pool - Part of \ref FuncNode, can be only used by a
-//! single function and added after the function epilog sequence (after
-//! `ret` instruction).
+//! - Local constant pool - Part of \ref FuncNode, can be only used by a single function and added after the
+//! function epilog sequence (after `ret` instruction).
//!
-//! - Global constant pool - Part of \ref BaseCompiler, flushed at the end
-//! of the generated code by \ref BaseEmitter::finalize().
+//! - Global constant pool - Part of \ref BaseCompiler, flushed at the end of the generated code by \ref
+//! BaseEmitter::finalize().
//!
//! The example below illustrates how a built-in constant pool can be used:
//!
@@ -342,13 +380,13 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! using namespace asmjit;
//!
//! static void exampleUseOfConstPool(x86::Compiler& cc) {
-//! cc.addFunc(FuncSignatureT<int>());
+//! cc.addFunc(FuncSignature::build<int>());
//!
//! x86::Gp v0 = cc.newGpd("v0");
//! x86::Gp v1 = cc.newGpd("v1");
//!
-//! x86::Mem c0 = cc.newInt32Const(ConstPool::kScopeLocal, 200);
-//! x86::Mem c1 = cc.newInt32Const(ConstPool::kScopeLocal, 33);
+//! x86::Mem c0 = cc.newInt32Const(ConstPoolScope::kLocal, 200);
+//! x86::Mem c1 = cc.newInt32Const(ConstPoolScope::kLocal, 33);
//!
//! cc.mov(v0, c0);
//! cc.mov(v1, c1);
@@ -361,16 +399,14 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//!
//! ### Jump Tables
//!
-//! x86::Compiler supports `jmp` instruction with reg/mem operand, which is a
-//! commonly used pattern to implement indirect jumps within a function, for
-//! example to implement `switch()` statement in a programming languages. By
-//! default AsmJit assumes that every basic block can be a possible jump
-//! target as it's unable to deduce targets from instruction's operands. This
-//! is a very pessimistic default that should be avoided if possible as it's
-//! costly and very unfriendly to liveness analysis and register allocation.
+//! x86::Compiler supports `jmp` instruction with reg/mem operand, which is a commonly used pattern to implement
+//! indirect jumps within a function, for example to implement `switch()` statement in a programming languages.
+//! By default AsmJit assumes that every basic block can be a possible jump target as it's unable to deduce targets
+//! from instruction's operands. This is a very pessimistic default that should be avoided if possible as it's costly
+//! and very unfriendly to liveness analysis and register allocation.
//!
-//! Instead of relying on such pessimistic default behavior, let's use \ref
-//! JumpAnnotation to annotate a jump where all targets are known:
+//! Instead of relying on such pessimistic default behavior, let's use \ref JumpAnnotation to annotate a jump where
+//! all targets are known:
//!
//! ```
//! #include <asmjit/x86.h>
@@ -378,7 +414,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! using namespace asmjit;
//!
//! static void exampleUseOfIndirectJump(x86::Compiler& cc) {
-//! cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost));
+//! FuncNode* funcNode = cc.addFunc(FuncSignature::build<float, float, float, uint32_t>());
//!
//! // Function arguments
//! x86::Xmm a = cc.newXmmSs("a");
@@ -395,13 +431,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! Label L_Div = cc.newLabel();
//! Label L_End = cc.newLabel();
//!
-//! cc.setArg(0, a);
-//! cc.setArg(1, b);
-//! cc.setArg(2, op);
+//! funcNode->setArg(0, a);
+//! funcNode->setArg(1, b);
+//! funcNode->setArg(2, op);
//!
-//! // Jump annotation is a building block that allows to annotate all
-//! // possible targets where `jmp()` can jump. It then drives the CFG
-//! // contruction and liveness analysis, which impacts register allocation.
+//! // Jump annotation is a building block that allows to annotate all possible targets where `jmp()` can
+//! // jump. It then drives the CFG construction and liveness analysis, which impacts register allocation.
//! JumpAnnotation* annotation = cc.newJumpAnnotation();
//! annotation->addLabel(L_Add);
//! annotation->addLabel(L_Sub);
@@ -459,7 +494,7 @@ public:
//! \{
ASMJIT_API explicit Compiler(CodeHolder* code = nullptr) noexcept;
- ASMJIT_API virtual ~Compiler() noexcept;
+ ASMJIT_API ~Compiler() noexcept override;
//! \}
@@ -467,52 +502,52 @@ public:
//! \{
#ifndef ASMJIT_NO_LOGGING
-# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
+# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
_newRegFmt(&OUT, PARAM, FORMAT, ARGS)
#else
-# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
- DebugUtils::unused(FORMAT); \
- DebugUtils::unused(std::forward<Args>(args)...); \
+# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
+ DebugUtils::unused(FORMAT); \
+ DebugUtils::unused(std::forward<Args>(args)...); \
_newReg(&OUT, PARAM)
#endif
-#define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \
- inline REG FUNC(uint32_t typeId) { \
- REG reg(Globals::NoInit); \
- _newReg(&reg, typeId); \
- return reg; \
- } \
- \
- template<typename... Args> \
- inline REG FUNC(uint32_t typeId, const char* fmt, Args&&... args) { \
- REG reg(Globals::NoInit); \
- ASMJIT_NEW_REG_FMT(reg, typeId, fmt, std::forward<Args>(args)...); \
- return reg; \
+#define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \
+ ASMJIT_INLINE_NODEBUG REG FUNC(TypeId typeId) { \
+ REG reg(Globals::NoInit); \
+ _newReg(&reg, typeId); \
+ return reg; \
+ } \
+ \
+ template<typename... Args> \
+ ASMJIT_INLINE_NODEBUG REG FUNC(TypeId typeId, const char* fmt, Args&&... args) { \
+ REG reg(Globals::NoInit); \
+ ASMJIT_NEW_REG_FMT(reg, typeId, fmt, std::forward<Args>(args)...); \
+ return reg; \
}
-#define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \
- inline REG FUNC() { \
- REG reg(Globals::NoInit); \
- _newReg(&reg, TYPE_ID); \
- return reg; \
- } \
- \
- template<typename... Args> \
- inline REG FUNC(const char* fmt, Args&&... args) { \
- REG reg(Globals::NoInit); \
- ASMJIT_NEW_REG_FMT(reg, TYPE_ID, fmt, std::forward<Args>(args)...); \
- return reg; \
+#define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \
+ ASMJIT_INLINE_NODEBUG REG FUNC() { \
+ REG reg(Globals::NoInit); \
+ _newReg(&reg, TYPE_ID); \
+ return reg; \
+ } \
+ \
+ template<typename... Args> \
+ ASMJIT_INLINE_NODEBUG REG FUNC(const char* fmt, Args&&... args) { \
+ REG reg(Globals::NoInit); \
+ ASMJIT_NEW_REG_FMT(reg, TYPE_ID, fmt, std::forward<Args>(args)...); \
+ return reg; \
}
template<typename RegT>
- inline RegT newSimilarReg(const RegT& ref) {
+ ASMJIT_INLINE_NODEBUG RegT newSimilarReg(const RegT& ref) {
RegT reg(Globals::NoInit);
- _newReg(reg, ref);
+ _newReg(&reg, ref);
return reg;
}
template<typename RegT, typename... Args>
- inline RegT newSimilarReg(const RegT& ref, const char* fmt, Args&&... args) {
+ ASMJIT_INLINE_NODEBUG RegT newSimilarReg(const RegT& ref, const char* fmt, Args&&... args) {
RegT reg(Globals::NoInit);
ASMJIT_NEW_REG_FMT(reg, ref, fmt, std::forward<Args>(args)...);
return reg;
@@ -523,46 +558,38 @@ public:
ASMJIT_NEW_REG_CUSTOM(newVec , Vec )
ASMJIT_NEW_REG_CUSTOM(newK , KReg)
- ASMJIT_NEW_REG_TYPED(newI8 , Gp , Type::kIdI8 )
- ASMJIT_NEW_REG_TYPED(newU8 , Gp , Type::kIdU8 )
- ASMJIT_NEW_REG_TYPED(newI16 , Gp , Type::kIdI16 )
- ASMJIT_NEW_REG_TYPED(newU16 , Gp , Type::kIdU16 )
- ASMJIT_NEW_REG_TYPED(newI32 , Gp , Type::kIdI32 )
- ASMJIT_NEW_REG_TYPED(newU32 , Gp , Type::kIdU32 )
- ASMJIT_NEW_REG_TYPED(newI64 , Gp , Type::kIdI64 )
- ASMJIT_NEW_REG_TYPED(newU64 , Gp , Type::kIdU64 )
- ASMJIT_NEW_REG_TYPED(newInt8 , Gp , Type::kIdI8 )
- ASMJIT_NEW_REG_TYPED(newUInt8 , Gp , Type::kIdU8 )
- ASMJIT_NEW_REG_TYPED(newInt16 , Gp , Type::kIdI16 )
- ASMJIT_NEW_REG_TYPED(newUInt16 , Gp , Type::kIdU16 )
- ASMJIT_NEW_REG_TYPED(newInt32 , Gp , Type::kIdI32 )
- ASMJIT_NEW_REG_TYPED(newUInt32 , Gp , Type::kIdU32 )
- ASMJIT_NEW_REG_TYPED(newInt64 , Gp , Type::kIdI64 )
- ASMJIT_NEW_REG_TYPED(newUInt64 , Gp , Type::kIdU64 )
- ASMJIT_NEW_REG_TYPED(newIntPtr , Gp , Type::kIdIntPtr )
- ASMJIT_NEW_REG_TYPED(newUIntPtr, Gp , Type::kIdUIntPtr)
-
- ASMJIT_NEW_REG_TYPED(newGpb , Gp , Type::kIdU8 )
- ASMJIT_NEW_REG_TYPED(newGpw , Gp , Type::kIdU16 )
- ASMJIT_NEW_REG_TYPED(newGpd , Gp , Type::kIdU32 )
- ASMJIT_NEW_REG_TYPED(newGpq , Gp , Type::kIdU64 )
- ASMJIT_NEW_REG_TYPED(newGpz , Gp , Type::kIdUIntPtr)
- ASMJIT_NEW_REG_TYPED(newXmm , Xmm , Type::kIdI32x4 )
- ASMJIT_NEW_REG_TYPED(newXmmSs , Xmm , Type::kIdF32x1 )
- ASMJIT_NEW_REG_TYPED(newXmmSd , Xmm , Type::kIdF64x1 )
- ASMJIT_NEW_REG_TYPED(newXmmPs , Xmm , Type::kIdF32x4 )
- ASMJIT_NEW_REG_TYPED(newXmmPd , Xmm , Type::kIdF64x2 )
- ASMJIT_NEW_REG_TYPED(newYmm , Ymm , Type::kIdI32x8 )
- ASMJIT_NEW_REG_TYPED(newYmmPs , Ymm , Type::kIdF32x8 )
- ASMJIT_NEW_REG_TYPED(newYmmPd , Ymm , Type::kIdF64x4 )
- ASMJIT_NEW_REG_TYPED(newZmm , Zmm , Type::kIdI32x16 )
- ASMJIT_NEW_REG_TYPED(newZmmPs , Zmm , Type::kIdF32x16 )
- ASMJIT_NEW_REG_TYPED(newZmmPd , Zmm , Type::kIdF64x8 )
- ASMJIT_NEW_REG_TYPED(newMm , Mm , Type::kIdMmx64 )
- ASMJIT_NEW_REG_TYPED(newKb , KReg, Type::kIdMask8 )
- ASMJIT_NEW_REG_TYPED(newKw , KReg, Type::kIdMask16 )
- ASMJIT_NEW_REG_TYPED(newKd , KReg, Type::kIdMask32 )
- ASMJIT_NEW_REG_TYPED(newKq , KReg, Type::kIdMask64 )
+ ASMJIT_NEW_REG_TYPED(newInt8 , Gp , TypeId::kInt8)
+ ASMJIT_NEW_REG_TYPED(newUInt8 , Gp , TypeId::kUInt8)
+ ASMJIT_NEW_REG_TYPED(newInt16 , Gp , TypeId::kInt16)
+ ASMJIT_NEW_REG_TYPED(newUInt16 , Gp , TypeId::kUInt16)
+ ASMJIT_NEW_REG_TYPED(newInt32 , Gp , TypeId::kInt32)
+ ASMJIT_NEW_REG_TYPED(newUInt32 , Gp , TypeId::kUInt32)
+ ASMJIT_NEW_REG_TYPED(newInt64 , Gp , TypeId::kInt64)
+ ASMJIT_NEW_REG_TYPED(newUInt64 , Gp , TypeId::kUInt64)
+ ASMJIT_NEW_REG_TYPED(newIntPtr , Gp , TypeId::kIntPtr)
+ ASMJIT_NEW_REG_TYPED(newUIntPtr, Gp , TypeId::kUIntPtr)
+
+ ASMJIT_NEW_REG_TYPED(newGpb , Gp , TypeId::kUInt8)
+ ASMJIT_NEW_REG_TYPED(newGpw , Gp , TypeId::kUInt16)
+ ASMJIT_NEW_REG_TYPED(newGpd , Gp , TypeId::kUInt32)
+ ASMJIT_NEW_REG_TYPED(newGpq , Gp , TypeId::kUInt64)
+ ASMJIT_NEW_REG_TYPED(newGpz , Gp , TypeId::kUIntPtr)
+ ASMJIT_NEW_REG_TYPED(newXmm , Xmm , TypeId::kInt32x4)
+ ASMJIT_NEW_REG_TYPED(newXmmSs , Xmm , TypeId::kFloat32x1)
+ ASMJIT_NEW_REG_TYPED(newXmmSd , Xmm , TypeId::kFloat64x1)
+ ASMJIT_NEW_REG_TYPED(newXmmPs , Xmm , TypeId::kFloat32x4)
+ ASMJIT_NEW_REG_TYPED(newXmmPd , Xmm , TypeId::kFloat64x2)
+ ASMJIT_NEW_REG_TYPED(newYmm , Ymm , TypeId::kInt32x8)
+ ASMJIT_NEW_REG_TYPED(newYmmPs , Ymm , TypeId::kFloat32x8)
+ ASMJIT_NEW_REG_TYPED(newYmmPd , Ymm , TypeId::kFloat64x4)
+ ASMJIT_NEW_REG_TYPED(newZmm , Zmm , TypeId::kInt32x16)
+ ASMJIT_NEW_REG_TYPED(newZmmPs , Zmm , TypeId::kFloat32x16)
+ ASMJIT_NEW_REG_TYPED(newZmmPd , Zmm , TypeId::kFloat64x8)
+ ASMJIT_NEW_REG_TYPED(newMm , Mm , TypeId::kMmx64)
+ ASMJIT_NEW_REG_TYPED(newKb , KReg, TypeId::kMask8)
+ ASMJIT_NEW_REG_TYPED(newKw , KReg, TypeId::kMask16)
+ ASMJIT_NEW_REG_TYPED(newKd , KReg, TypeId::kMask32)
+ ASMJIT_NEW_REG_TYPED(newKq , KReg, TypeId::kMask64)
#undef ASMJIT_NEW_REG_TYPED
#undef ASMJIT_NEW_REG_CUSTOM
@@ -574,7 +601,7 @@ public:
//! \{
//! Creates a new memory chunk allocated on the current function's stack.
- inline Mem newStack(uint32_t size, uint32_t alignment, const char* name = nullptr) {
+ ASMJIT_INLINE_NODEBUG Mem newStack(uint32_t size, uint32_t alignment, const char* name = nullptr) {
Mem m(Globals::NoInit);
_newStack(&m, size, alignment, name);
return m;
@@ -586,49 +613,38 @@ public:
//! \{
//! Put data to a constant-pool and get a memory reference to it.
- inline Mem newConst(uint32_t scope, const void* data, size_t size) {
+ ASMJIT_INLINE_NODEBUG Mem newConst(ConstPoolScope scope, const void* data, size_t size) {
Mem m(Globals::NoInit);
_newConst(&m, scope, data, size);
return m;
}
//! Put a BYTE `val` to a constant-pool.
- inline Mem newByteConst(uint32_t scope, uint8_t val) noexcept { return newConst(scope, &val, 1); }
+ ASMJIT_INLINE_NODEBUG Mem newByteConst(ConstPoolScope scope, uint8_t val) noexcept { return newConst(scope, &val, 1); }
//! Put a WORD `val` to a constant-pool.
- inline Mem newWordConst(uint32_t scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
+ ASMJIT_INLINE_NODEBUG Mem newWordConst(ConstPoolScope scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
//! Put a DWORD `val` to a constant-pool.
- inline Mem newDWordConst(uint32_t scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
+ ASMJIT_INLINE_NODEBUG Mem newDWordConst(ConstPoolScope scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
//! Put a QWORD `val` to a constant-pool.
- inline Mem newQWordConst(uint32_t scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
+ ASMJIT_INLINE_NODEBUG Mem newQWordConst(ConstPoolScope scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
//! Put a WORD `val` to a constant-pool.
- inline Mem newInt16Const(uint32_t scope, int16_t val) noexcept { return newConst(scope, &val, 2); }
+ ASMJIT_INLINE_NODEBUG Mem newInt16Const(ConstPoolScope scope, int16_t val) noexcept { return newConst(scope, &val, 2); }
//! Put a WORD `val` to a constant-pool.
- inline Mem newUInt16Const(uint32_t scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
+ ASMJIT_INLINE_NODEBUG Mem newUInt16Const(ConstPoolScope scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
//! Put a DWORD `val` to a constant-pool.
- inline Mem newInt32Const(uint32_t scope, int32_t val) noexcept { return newConst(scope, &val, 4); }
+ ASMJIT_INLINE_NODEBUG Mem newInt32Const(ConstPoolScope scope, int32_t val) noexcept { return newConst(scope, &val, 4); }
//! Put a DWORD `val` to a constant-pool.
- inline Mem newUInt32Const(uint32_t scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
+ ASMJIT_INLINE_NODEBUG Mem newUInt32Const(ConstPoolScope scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
//! Put a QWORD `val` to a constant-pool.
- inline Mem newInt64Const(uint32_t scope, int64_t val) noexcept { return newConst(scope, &val, 8); }
+ ASMJIT_INLINE_NODEBUG Mem newInt64Const(ConstPoolScope scope, int64_t val) noexcept { return newConst(scope, &val, 8); }
//! Put a QWORD `val` to a constant-pool.
- inline Mem newUInt64Const(uint32_t scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
+ ASMJIT_INLINE_NODEBUG Mem newUInt64Const(ConstPoolScope scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
//! Put a SP-FP `val` to a constant-pool.
- inline Mem newFloatConst(uint32_t scope, float val) noexcept { return newConst(scope, &val, 4); }
+ ASMJIT_INLINE_NODEBUG Mem newFloatConst(ConstPoolScope scope, float val) noexcept { return newConst(scope, &val, 4); }
//! Put a DP-FP `val` to a constant-pool.
- inline Mem newDoubleConst(uint32_t scope, double val) noexcept { return newConst(scope, &val, 8); }
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("newMmConst() uses a deprecated Data64, use newConst() with your own data instead")
- inline Mem newMmConst(uint32_t scope, const Data64& val) noexcept { return newConst(scope, &val, 8); }
-
- ASMJIT_DEPRECATED("newXmmConst() uses a deprecated Data128, use newConst() with your own data instead")
- inline Mem newXmmConst(uint32_t scope, const Data128& val) noexcept { return newConst(scope, &val, 16); }
-
- ASMJIT_DEPRECATED("newYmmConst() uses a deprecated Data256, use newConst() with your own data instead")
- inline Mem newYmmConst(uint32_t scope, const Data256& val) noexcept { return newConst(scope, &val, 32); }
-#endif // !ASMJIT_NO_DEPRECATED
+ ASMJIT_INLINE_NODEBUG Mem newDoubleConst(ConstPoolScope scope, double val) noexcept { return newConst(scope, &val, 8); }
//! \}
@@ -636,9 +652,9 @@ public:
//! \{
//! Force the compiler to not follow the conditional or unconditional jump.
- inline Compiler& unfollow() noexcept { _instOptions |= Inst::kOptionUnfollow; return *this; }
+ ASMJIT_INLINE_NODEBUG Compiler& unfollow() noexcept { addInstOptions(InstOptions::kUnfollow); return *this; }
//! Tell the compiler that the destination variable will be overwritten.
- inline Compiler& overwrite() noexcept { _instOptions |= Inst::kOptionOverwrite; return *this; }
+ ASMJIT_INLINE_NODEBUG Compiler& overwrite() noexcept { addInstOptions(InstOptions::kOverwrite); return *this; }
//! \}
@@ -646,43 +662,31 @@ public:
//! \{
//! Invoke a function call without `target` type enforcement.
- inline Error invoke_(InvokeNode** out, const Operand_& target, const FuncSignature& signature) {
- return _addInvokeNode(out, Inst::kIdCall, target, signature);
+ ASMJIT_INLINE_NODEBUG Error invoke_(InvokeNode** out, const Operand_& target, const FuncSignature& signature) {
+ return addInvokeNode(out, Inst::kIdCall, target, signature);
}
- //! Invoke a function call of the given `target` and `signature` and store
- //! the added node to `out`.
+ //! Invoke a function call of the given `target` and `signature` and store the added node to `out`.
//!
- //! Creates a new \ref InvokeNode, initializes all the necessary members to
- //! match the given function `signature`, adds the node to the compiler, and
- //! stores its pointer to `out`. The operation is atomic, if anything fails
+ //! Creates a new \ref InvokeNode, initializes all the necessary members to match the given function `signature`,
+ //! adds the node to the compiler, and stores its pointer to `out`. The operation is atomic, if anything fails
//! nullptr is stored in `out` and error code is returned.
- inline Error invoke(InvokeNode** out, const Gp& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
+ ASMJIT_INLINE_NODEBUG Error invoke(InvokeNode** out, const Gp& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
//! \overload
- inline Error invoke(InvokeNode** out, const Mem& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
+ ASMJIT_INLINE_NODEBUG Error invoke(InvokeNode** out, const Mem& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
//! \overload
- inline Error invoke(InvokeNode** out, const Label& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
+ ASMJIT_INLINE_NODEBUG Error invoke(InvokeNode** out, const Label& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
//! \overload
- inline Error invoke(InvokeNode** out, const Imm& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
+ ASMJIT_INLINE_NODEBUG Error invoke(InvokeNode** out, const Imm& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
//! \overload
- inline Error invoke(InvokeNode** out, uint64_t target, const FuncSignature& signature) { return invoke_(out, Imm(int64_t(target)), signature); }
-
-#ifndef _DOXYGEN
- template<typename Target>
- ASMJIT_DEPRECATED("Use invoke() instead of call()")
- inline InvokeNode* call(const Target& target, const FuncSignature& signature) {
- InvokeNode* invokeNode;
- invoke(&invokeNode, target, signature);
- return invokeNode;
- }
-#endif
+ ASMJIT_INLINE_NODEBUG Error invoke(InvokeNode** out, uint64_t target, const FuncSignature& signature) { return invoke_(out, Imm(int64_t(target)), signature); }
- //! Return.
- inline FuncRetNode* ret() { return addRet(Operand(), Operand()); }
+ //! Return from function.
+ ASMJIT_INLINE_NODEBUG Error ret() { return addRet(Operand(), Operand()); }
//! \overload
- inline FuncRetNode* ret(const BaseReg& o0) { return addRet(o0, Operand()); }
+ ASMJIT_INLINE_NODEBUG Error ret(const BaseReg& o0) { return addRet(o0, Operand()); }
//! \overload
- inline FuncRetNode* ret(const BaseReg& o0, const BaseReg& o1) { return addRet(o0, o1); }
+ ASMJIT_INLINE_NODEBUG Error ret(const BaseReg& o0, const BaseReg& o1) { return addRet(o0, o1); }
//! \}
@@ -692,23 +696,24 @@ public:
using EmitterExplicitT<Compiler>::jmp;
//! Adds a jump to the given `target` with the provided jump `annotation`.
- inline Error jmp(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
+ ASMJIT_INLINE_NODEBUG Error jmp(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
//! \overload
- inline Error jmp(const BaseMem& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
+ ASMJIT_INLINE_NODEBUG Error jmp(const BaseMem& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
//! \}
- //! \name Finalize
+ //! \name Events
//! \{
- ASMJIT_API Error finalize() override;
+ ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
+ ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
//! \}
- //! \name Events
+ //! \name Finalize
//! \{
- ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
+ ASMJIT_API Error finalize() override;
//! \}
};