LCOV - code coverage report
Current view: top level - asmjit - x86assembler.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 2 2 100.0 %
Date: 2026-11-05 10:19:06 Functions: 0 0 -

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_X86_X86ASSEMBLER_H_INCLUDED
       8             : #define ASMJIT_X86_X86ASSEMBLER_H_INCLUDED
       9             : 
      10             : #include "assembler.h"
      11             : #include "x86emitter.h"
      12             : #include "x86operand.h"
      13             : 
      14             : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
      15             : 
      16             : //! \addtogroup asmjit_x86
      17             : //! \{
      18             : 
      19             : //! X86/X64 assembler implementation.
      20             : //!
      21             : //! x86::Assembler is a code emitter that emits machine code directly into the \ref CodeBuffer. The assembler is capable
      22             : //! of targeting both 32-bit and 64-bit instruction sets, the instruction set can be configured through \ref CodeHolder.
      23             : //!
      24             : //! ### Basics
      25             : //!
      26             : //! The following example shows a basic use of `x86::Assembler`, how to generate a function that works in both 32-bit
      27             : //! and 64-bit modes, and how to connect \ref JitRuntime, \ref CodeHolder, and `x86::Assembler`.
      28             : //!
      29             : //! ```
      30             : //! #include <asmjit/x86.h>
      31             : //! #include <stdio.h>
      32             : //!
      33             : //! using namespace asmjit;
      34             : //!
      35             : //! // Signature of the generated function.
      36             : //! typedef int (*SumFunc)(const int* arr, size_t count);
      37             : //!
      38             : //! int main() {
      39             : //!   JitRuntime rt;                    // Create a runtime specialized for JIT.
      40             : //!   CodeHolder code;                  // Create a CodeHolder.
      41             : //!
      42             : //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
      43             : //!   x86::Assembler a(&code);          // Create and attach x86::Assembler to code.
      44             : //!
      45             : //!   // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions:
      46             : //!   //   32-BIT - passed all arguments by stack.
      47             : //!   //   WIN64  - passes first 4 arguments by RCX, RDX, R8, and R9.
      48             : //!   //   UNIX64 - passes first 6 arguments by RDI, RSI, RCX, RDX, R8, and R9.
      49             : //!   x86::Gp arr, cnt;
      50             : //!   x86::Gp sum = x86::eax;           // Use EAX as 'sum' as it's a return register.
      51             : //!
      52             : //!   if (ASMJIT_ARCH_BITS == 64) {
      53             : //!   #if defined(_WIN32)
      54             : //!     arr = x86::rcx;                 // First argument (array ptr).
      55             : //!     cnt = x86::rdx;                 // Second argument (number of elements)
      56             : //!   #else
      57             : //!     arr = x86::rdi;                 // First argument (array ptr).
      58             : //!     cnt = x86::rsi;                 // Second argument (number of elements)
      59             : //!   #endif
      60             : //!   }
      61             : //!   else {
      62             : //!     arr = x86::edx;                 // Use EDX to hold the array pointer.
      63             : //!     cnt = x86::ecx;                 // Use ECX to hold the counter.
      64             : //!     // Fetch first and second arguments from [ESP + 4] and [ESP + 8].
      65             : //!     a.mov(arr, x86::ptr(x86::esp, 4));
      66             : //!     a.mov(cnt, x86::ptr(x86::esp, 8));
      67             : //!   }
      68             : //!
      69             : //!   Label Loop = a.newLabel();        // To construct the loop, we need some labels.
      70             : //!   Label Exit = a.newLabel();
      71             : //!
      72             : //!   a.xor_(sum, sum);                 // Clear 'sum' register (shorter than 'mov').
      73             : //!   a.test(cnt, cnt);                 // Border case:
      74             : //!   a.jz(Exit);                       //   If 'cnt' is zero jump to 'Exit' now.
      75             : //!
      76             : //!   a.bind(Loop);                     // Start of a loop iteration.
      77             : //!   a.add(sum, x86::dword_ptr(arr));  // Add int at [arr] to 'sum'.
      78             : //!   a.add(arr, 4);                    // Increment 'arr' pointer.
      79             : //!   a.dec(cnt);                       // Decrease 'cnt'.
      80             : //!   a.jnz(Loop);                      // If not zero jump to 'Loop'.
      81             : //!
      82             : //!   a.bind(Exit);                     // Exit to handle the border case.
      83             : //!   a.ret();                          // Return from function ('sum' == 'eax').
      84             : //!   // ----> x86::Assembler is no longer needed from here and can be destroyed <----
      85             : //!
      86             : //!   SumFunc fn;
      87             : //!   Error err = rt.add(&fn, &code);   // Add the generated code to the runtime.
      88             : //!
      89             : //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
      90             : //!   // ----> CodeHolder is no longer needed from here and can be destroyed <----
      91             : //!
      92             : //!   static const int array[6] = { 4, 8, 15, 16, 23, 42 };
      93             : //!
      94             : //!   int result = fn(array, 6);        // Execute the generated code.
      95             : //!   printf("%d\n", result);           // Print sum of array (108).
      96             : //!
      97             : //!   rt.release(fn);                   // Explicitly remove the function from the runtime
      98             : //!   return 0;                         // Everything successful...
      99             : //! }
     100             : //! ```
     101             : //!
     102             : //! The example should be self-explanatory. It shows how to work with labels, how to use operands, and how to emit
     103             : //! instructions that can use different registers based on runtime selection. It implements 32-bit CDECL, WIN64,
     104             : //! and SysV64 caling conventions and will work on most X86/X64 environments.
     105             : //!
     106             : //! Although functions prologs / epilogs can be implemented manually, AsmJit provides utilities that can be used
     107             : //! to create function prologs and epilogs automatically, see \ref asmjit_function for more details.
     108             : //!
     109             : //! ### Instruction Validation
     110             : //!
     111             : //! Assembler prefers speed over strictness by default. The implementation checks the type of operands and fails
     112             : //! if the signature of types is invalid, however, it does only basic checks regarding registers and their groups
     113             : //! used in instructions. It's possible to pass operands that don't form any valid signature to the implementation
     114             : //! and succeed. This is usually not a problem as Assembler provides typed API so operand types are normally checked
     115             : //! by C++ compiler at compile time, however, Assembler is fully dynamic and its \ref emit() function can be called
     116             : //! with any instruction id, options, and operands. Moreover, it's also possible to form instructions that will be
     117             : //! accepted by the typed API, for example by calling `mov(x86::eax, x86::al)` - the C++ compiler won't see a problem
     118             : //! as both EAX and AL are \ref Gp registers.
     119             : //!
     120             : //! To help with common mistakes AsmJit allows to activate instruction validation. This feature instruments
     121             : //! the Assembler to call \ref InstAPI::validate() before it attempts to encode any instruction.
     122             : //!
     123             : //! The example below illustrates how validation can be turned on:
     124             : //!
     125             : //! ```
     126             : //! #include <asmjit/x86.h>
     127             : //! #include <stdio.h>
     128             : //!
     129             : //! using namespace asmjit;
     130             : //!
     131             : //! int main(int argc, char* argv[]) {
     132             : //!   JitRuntime rt;                    // Create a runtime specialized for JIT.
     133             : //!   CodeHolder code;                  // Create a CodeHolder.
     134             : //!
     135             : //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
     136             : //!   x86::Assembler a(&code);          // Create and attach x86::Assembler to code.
     137             : //!
     138             : //!   // Enable strict validation.
     139             : //!   a.addDiagnosticOptions(DiagnosticOptions::kValidateAssembler);
     140             : //!
     141             : //!   // Try to encode invalid or ill-formed instructions.
     142             : //!   Error err;
     143             : //!
     144             : //!   // Invalid instruction.
     145             : //!   err = a.mov(x86::eax, x86::al);
     146             : //!   printf("Status: %s\n", DebugUtils::errorAsString(err));
     147             : //!
     148             : //!   // Invalid instruction.
     149             : //!   err = a.emit(x86::Inst::kIdMovss, x86::eax, x86::xmm0);
     150             : //!   printf("Status: %s\n", DebugUtils::errorAsString(err));
     151             : //!
     152             : //!   // Ambiguous operand size - the pointer requires size.
     153             : //!   err = a.inc(x86::ptr(x86::rax), 1);
     154             : //!   printf("Status: %s\n", DebugUtils::errorAsString(err));
     155             : //!
     156             : //!   return 0;
     157             : //! }
     158             : //! ```
     159             : //!
     160             : //! ### Native Registers
     161             : //!
     162             : //! All emitters provide functions to construct machine-size registers depending on the target. This feature is
     163             : //! for users that want to write code targeting both 32-bit and 64-bit architectures at the same time. In AsmJit
     164             : //! terminology such registers have prefix `z`, so for example on X86 architecture the following native registers
     165             : //! are provided:
     166             : //!
     167             : //!   - `zax` - mapped to either `eax` or `rax`
     168             : //!   - `zbx` - mapped to either `ebx` or `rbx`
     169             : //!   - `zcx` - mapped to either `ecx` or `rcx`
     170             : //!   - `zdx` - mapped to either `edx` or `rdx`
     171             : //!   - `zsp` - mapped to either `esp` or `rsp`
     172             : //!   - `zbp` - mapped to either `ebp` or `rbp`
     173             : //!   - `zsi` - mapped to either `esi` or `rsi`
     174             : //!   - `zdi` - mapped to either `edi` or `rdi`
     175             : //!
     176             : //! They are accessible through \ref x86::Assembler, \ref x86::Builder, and \ref x86::Compiler. The example below
     177             : //! illustrates how to use this feature:
     178             : //!
     179             : //! ```
     180             : //! #include <asmjit/x86.h>
     181             : //! #include <stdio.h>
     182             : //!
     183             : //! using namespace asmjit;
     184             : //!
     185             : //! typedef int (*Func)(void);
     186             : //!
     187             : //! int main(int argc, char* argv[]) {
     188             : //!   JitRuntime rt;                    // Create a runtime specialized for JIT.
     189             : //!   CodeHolder code;                  // Create a CodeHolder.
     190             : //!
     191             : //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
     192             : //!   x86::Assembler a(&code);          // Create and attach x86::Assembler to code.
     193             : //!
     194             : //!   // Let's get these registers from x86::Assembler.
     195             : //!   x86::Gp zbp = a.zbp();
     196             : //!   x86::Gp zsp = a.zsp();
     197             : //!
     198             : //!   int stackSize = 32;
     199             : //!
     200             : //!   // Function prolog.
     201             : //!   a.push(zbp);
     202             : //!   a.mov(zbp, zsp);
     203             : //!   a.sub(zsp, stackSize);
     204             : //!
     205             : //!   // ... emit some code (this just sets return value to zero) ...
     206             : //!   a.xor_(x86::eax, x86::eax);
     207             : //!
     208             : //!   // Function epilog and return.
     209             : //!   a.mov(zsp, zbp);
     210             : //!   a.pop(zbp);
     211             : //!   a.ret();
     212             : //!
     213             : //!   // To make the example complete let's call it.
     214             : //!   Func fn;
     215             : //!   Error err = rt.add(&fn, &code);   // Add the generated code to the runtime.
     216             : //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
     217             : //!
     218             : //!   int result = fn();                // Execute the generated code.
     219             : //!   printf("%d\n", result);           // Print the resulting "0".
     220             : //!
     221             : //!   rt.release(fn);                   // Remove the function from the runtime.
     222             : //!   return 0;
     223             : //! }
     224             : //! ```
     225             : //!
     226             : //! The example just returns `0`, but the function generated contains a standard prolog and epilog sequence and the
     227             : //! function itself reserves 32 bytes of local stack. The advantage is clear - a single code-base can handle multiple
     228             : //! targets easily. If you want to create a register of native size dynamically by specifying its id it's also possible:
     229             : //!
     230             : //! ```
     231             : //! void example(x86::Assembler& a) {
     232             : //!   x86::Gp zax = a.gpz(x86::Gp::kIdAx);
     233             : //!   x86::Gp zbx = a.gpz(x86::Gp::kIdBx);
     234             : //!   x86::Gp zcx = a.gpz(x86::Gp::kIdCx);
     235             : //!   x86::Gp zdx = a.gpz(x86::Gp::kIdDx);
     236             : //!
     237             : //!   // You can also change register's id easily.
     238             : //!   x86::Gp zsp = zax;
     239             : //!   zsp.setId(4); // or x86::Gp::kIdSp.
     240             : //! }
     241             : //! ```
     242             : //!
     243             : //! ### Data Embedding
     244             : //!
     245             : //! x86::Assembler extends the standard \ref BaseAssembler with X86/X64 specific conventions that are often used by
     246             : //! assemblers to embed data next to the code. The following functions can be used to embed data:
     247             : //!
     248             : //!   - \ref BaseAssembler::embedInt8() - embeds int8_t (portable naming).
     249             : //!   - \ref BaseAssembler::embedUInt8() - embeds uint8_t (portable naming).
     250             : //!   - \ref BaseAssembler::embedInt16() - embeds int16_t (portable naming).
     251             : //!   - \ref BaseAssembler::embedUInt16() - embeds uint16_t (portable naming).
     252             : //!   - \ref BaseAssembler::embedInt32() - embeds int32_t (portable naming).
     253             : //!   - \ref BaseAssembler::embedUInt32() - embeds uint32_t (portable naming).
     254             : //!   - \ref BaseAssembler::embedInt64() - embeds int64_t (portable naming).
     255             : //!   - \ref BaseAssembler::embedUInt64() - embeds uint64_t (portable naming).
     256             : //!   - \ref BaseAssembler::embedFloat() - embeds float (portable naming).
     257             : //!   - \ref BaseAssembler::embedDouble() - embeds double (portable naming).
     258             : //!
     259             : //!   - \ref x86::Assembler::db() - embeds byte (8 bits) (x86 naming).
     260             : //!   - \ref x86::Assembler::dw() - embeds word (16 bits) (x86 naming).
     261             : //!   - \ref x86::Assembler::dd() - embeds dword (32 bits) (x86 naming).
     262             : //!   - \ref x86::Assembler::dq() - embeds qword (64 bits) (x86 naming).
     263             : //!
     264             : //! The following example illustrates how embed works:
     265             : //!
     266             : //! ```
     267             : //! #include <asmjit/x86.h>
     268             : //! using namespace asmjit;
     269             : //!
     270             : //! void embedData(x86::Assembler& a) {
     271             : //!   a.db(0xFF);         // Embeds 0xFF byte.
     272             : //!   a.dw(0xFF00);       // Embeds 0xFF00 word (little-endian).
     273             : //!   a.dd(0xFF000000);   // Embeds 0xFF000000 dword (little-endian).
     274             : //!   a.embedFloat(0.4f); // Embeds 0.4f (32-bit float, little-endian).
     275             : //! }
     276             : //! ```
     277             : //!
     278             : //! Sometimes it's required to read the data that is embedded after code, for example. This can be done through
     279             : //! \ref Label as shown below:
     280             : //!
     281             : //! ```
     282             : //! #include <asmjit/x86.h>
     283             : //! using namespace asmjit;
     284             : //!
     285             : //! void embedData(x86::Assembler& a, const Label& L_Data) {
     286             : //!   x86::Gp addr = a.zax();  // EAX or RAX.
     287             : //!   x86::Gp val = x86::edi;  // Where to store some value...
     288             : //!
     289             : //!   // Approach 1 - Load the address to register through LEA. This approach
     290             : //!   //              is flexible as the address can be then manipulated, for
     291             : //!   //              example if you have a data array, which would need index.
     292             : //!   a.lea(addr, L_Data);     // Loads the address of the label to EAX or RAX.
     293             : //!   a.mov(val, dword_ptr(addr));
     294             : //!
     295             : //!   // Approach 2 - Load the data directly by using L_Data in address. It's
     296             : //!   //              worth noting that this doesn't work with indexes in X64
     297             : //!   //              mode. It will use absolute address in 32-bit mode and
     298             : //!   //              relative address (RIP) in 64-bit mode.
     299             : //!   a.mov(val, dword_ptr(L_Data));
     300             : //! }
     301             : //! ```
     302             : //!
     303             : //! ### Label Embedding
     304             : //!
     305             : //! It's also possible to embed labels. In general AsmJit provides the following options:
     306             : //!
     307             : //!   - \ref BaseEmitter::embedLabel() - Embeds absolute address of a label. This is target dependent and would
     308             : //!     embed either 32-bit or 64-bit data that embeds absolute label address. This kind of embedding cannot be
     309             : //!     used in a position independent code.
     310             : //!
     311             : //!   - \ref BaseEmitter::embedLabelDelta() - Embeds a difference between two labels. The size of the difference
     312             : //!     can be specified so it's possible to embed 8-bit, 16-bit, 32-bit, and 64-bit difference, which is sufficient
     313             : //!     for most purposes.
     314             : //!
     315             : //! The following example demonstrates how to embed labels and their differences:
     316             : //!
     317             : //! ```
     318             : //! #include <asmjit/x86.h>
     319             : //! using namespace asmjit;
     320             : //!
     321             : //! void embedLabel(x86::Assembler& a, const Label& L_Data) {
     322             : //!   // [1] Embed L_Data - the size of the data will be dependent on the target.
     323             : //!   a.embedLabel(L_Data);
     324             : //!
     325             : //!   // [2] Embed a 32-bit difference of two labels.
     326             : //!   Label L_Here = a.newLabel();
     327             : //!   a.bind(L_Here);
     328             : //!   // Embeds int32_t(L_Data - L_Here).
     329             : //!   a.embedLabelDelta(L_Data, L_Here, 4);
     330             : //! }
     331             : //! ```
     332             : //!
     333             : //! ### Using FuncFrame and FuncDetail with x86::Assembler
     334             : //!
     335             : //! The example below demonstrates how \ref FuncFrame and \ref FuncDetail can be used together with \ref x86::Assembler
     336             : //! to generate a function that will use platform dependent calling conventions automatically depending on the target:
     337             : //!
     338             : //! ```
     339             : //! #include <asmjit/x86.h>
     340             : //! #include <stdio.h>
     341             : //!
     342             : //! using namespace asmjit;
     343             : //!
     344             : //! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b);
     345             : //!
     346             : //! int main(int argc, char* argv[]) {
     347             : //!   JitRuntime rt;                    // Create JIT Runtime.
     348             : //!   CodeHolder code;                  // Create a CodeHolder.
     349             : //!
     350             : //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
     351             : //!   x86::Assembler a(&code);          // Create and attach x86::Assembler to code.
     352             : //!
     353             : //!   // Decide which registers will be mapped to function arguments. Try changing
     354             : //!   // registers of dst, src_a, and src_b and see what happens in function's
     355             : //!   // prolog and epilog.
     356             : //!   x86::Gp dst   = a.zax();
     357             : //!   x86::Gp src_a = a.zcx();
     358             : //!   x86::Gp src_b = a.zdx();
     359             : //!
     360             : //!   X86::Xmm vec0 = x86::xmm0;
     361             : //!   X86::Xmm vec1 = x86::xmm1;
     362             : //!
     363             : //!   // Create/initialize FuncDetail and FuncFrame.
     364             : //!   FuncDetail func;
     365             : //!   func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConvId::kHost));
     366             : //!
     367             : //!   FuncFrame frame;
     368             : //!   frame.init(func);
     369             : //!
     370             : //!   // Make XMM0 and XMM1 dirty - RegGroup::kVec describes XMM|YMM|ZMM registers.
     371             : //!   frame.setDirtyRegs(RegGroup::kVec, IntUtils::mask(0, 1));
     372             : //!
     373             : //!   // Alternatively, if you don't want to use register masks you can pass BaseReg
     374             : //!   // to addDirtyRegs(). The following code would add both xmm0 and xmm1.
     375             : //!   frame.addDirtyRegs(x86::xmm0, x86::xmm1);
     376             : //!
     377             : //!   FuncArgsAssignment args(&func);   // Create arguments assignment context.
     378             : //!   args.assignAll(dst, src_a, src_b);// Assign our registers to arguments.
     379             : //!   args.updateFrameInfo(frame);      // Reflect our args in FuncFrame.
     380             : //!   frame.finalize();                 // Finalize the FuncFrame (updates it).
     381             : //!
     382             : //!   a.emitProlog(frame);              // Emit function prolog.
     383             : //!   a.emitArgsAssignment(frame, args);// Assign arguments to registers.
     384             : //!   a.movdqu(vec0, x86::ptr(src_a));  // Load 4 ints from [src_a] to XMM0.
     385             : //!   a.movdqu(vec1, x86::ptr(src_b));  // Load 4 ints from [src_b] to XMM1.
     386             : //!   a.paddd(vec0, vec1);              // Add 4 ints in XMM1 to XMM0.
     387             : //!   a.movdqu(x86::ptr(dst), vec0);    // Store the result to [dst].
     388             : //!   a.emitEpilog(frame);              // Emit function epilog and return.
     389             : //!
     390             : //!   SumIntsFunc fn;
     391             : //!   Error err = rt.add(&fn, &code);   // Add the generated code to the runtime.
     392             : //!   if (err) return 1;                // Handle a possible error case.
     393             : //!
     394             : //!   // Execute the generated function.
     395             : //!   int inA[4] = { 4, 3, 2, 1 };
     396             : //!   int inB[4] = { 1, 5, 2, 8 };
     397             : //!   int out[4];
     398             : //!   fn(out, inA, inB);
     399             : //!
     400             : //!   // Prints {5 8 4 9}
     401             : //!   printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]);
     402             : //!
     403             : //!   rt.release(fn);
     404             : //!   return 0;
     405             : //! }
     406             : //! ```
     407             : //!
     408             : //! ### Using x86::Assembler as Code-Patcher
     409             : //!
     410             : //! This is an advanced topic that is sometimes unavoidable. AsmJit by default appends machine code it generates
     411             : //! into a \ref CodeBuffer, however, it also allows to set the offset in \ref CodeBuffer explicitly and to overwrite
     412             : //! its content. This technique is extremely dangerous as X86 instructions have variable length (see below), so you
     413             : //! should in general only patch code to change instruction's immediate values or some other details not known the
     414             : //! at a time the instruction was emitted. A typical scenario that requires code-patching is when you start emitting
     415             : //! function and you don't know how much stack you want to reserve for it.
     416             : //!
     417             : //! Before we go further it's important to introduce instruction options, because they can help with code-patching
     418             : //! (and not only patching, but that will be explained in AVX-512 section):
     419             : //!
     420             : //!   - Many general-purpose instructions (especially arithmetic ones) on X86 have multiple encodings - in AsmJit
     421             : //!     this is usually called 'short form' and 'long form'.
     422             : //!
     423             : //!   - AsmJit always tries to use 'short form' as it makes the resulting machine-code smaller, which is always
     424             : //!     good - this decision is used by majority of assemblers out there.
     425             : //!
     426             : //!   - AsmJit allows to override the default decision by using `short_()` and `long_()` instruction options to force
     427             : //!     short or long form, respectively. The most useful is `long_()` as it basically forces AsmJit to always emit
     428             : //!     the longest form. The `short_()` is not that useful as it's automatic (except jumps to non-bound labels). Note
     429             : //!     that the underscore after each function name avoids collision with built-in C++ types.
     430             : //!
     431             : //! To illustrate what short form and long form means in binary let's assume we want to emit "add esp, 16" instruction,
     432             : //! which has two possible binary encodings:
     433             : //!
     434             : //!   - `83C410` - This is a short form aka `short add esp, 16` - You can see opcode byte (0x8C), MOD/RM byte (0xC4)
     435             : //!     and an 8-bit immediate value representing `16`.
     436             : //!
     437             : //!   - `81C410000000` - This is a long form aka `long add esp, 16` - You can see a different opcode byte (0x81), the
     438             : //!     same Mod/RM byte (0xC4) and a 32-bit immediate in little-endian representing `16`.
     439             : //!
     440             : //! It should be obvious that patching an existing instruction into an instruction having a different size may create
     441             : //! various problems. So it's recommended to be careful and to only patch instructions into instructions having the
     442             : //! same size. The example below demonstrates how instruction options can be used to guarantee the size of an
     443             : //! instruction by forcing the assembler to use long-form encoding:
     444             : //!
     445             : //! ```
     446             : //! #include <asmjit/x86.h>
     447             : //! #include <stdio.h>
     448             : //!
     449             : //! using namespace asmjit;
     450             : //!
     451             : //! typedef int (*Func)(void);
     452             : //!
     453             : //! int main(int argc, char* argv[]) {
     454             : //!   JitRuntime rt;                    // Create a runtime specialized for JIT.
     455             : //!   CodeHolder code;                  // Create a CodeHolder.
     456             : //!
     457             : //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
     458             : //!   x86::Assembler a(&code);          // Create and attach x86::Assembler to code.
     459             : //!
     460             : //!   // Let's get these registers from x86::Assembler.
     461             : //!   x86::Gp zbp = a.zbp();
     462             : //!   x86::Gp zsp = a.zsp();
     463             : //!
     464             : //!   // Function prolog.
     465             : //!   a.push(zbp);
     466             : //!   a.mov(zbp, zsp);
     467             : //!
     468             : //!   // This is where we are gonna patch the code later, so let's get the offset
     469             : //!   // (the current location) from the beginning of the code-buffer.
     470             : //!   size_t patchOffset = a.offset();
     471             : //!   // Let's just emit 'sub zsp, 0' for now, but don't forget to use LONG form.
     472             : //!   a.long_().sub(zsp, 0);
     473             : //!
     474             : //!   // ... emit some code (this just sets return value to zero) ...
     475             : //!   a.xor_(x86::eax, x86::eax);
     476             : //!
     477             : //!   // Function epilog and return.
     478             : //!   a.mov(zsp, zbp);
     479             : //!   a.pop(zbp);
     480             : //!   a.ret();
     481             : //!
     482             : //!   // Now we know how much stack size we want to reserve. I have chosen 128
     483             : //!   // bytes on purpose as it's encodable only in long form that we have used.
     484             : //!
     485             : //!   int stackSize = 128;              // Number of bytes to reserve on the stack.
     486             : //!   a.setOffset(patchOffset);         // Move the current cursor to `patchOffset`.
     487             : //!   a.long_().sub(zsp, stackSize);    // Patch the code; don't forget to use LONG form.
     488             : //!
     489             : //!   // Now the code is ready to be called
     490             : //!   Func fn;
     491             : //!   Error err = rt.add(&fn, &code);   // Add the generated code to the runtime.
     492             : //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
     493             : //!
     494             : //!   int result = fn();                // Execute the generated code.
     495             : //!   printf("%d\n", result);           // Print the resulting "0".
     496             : //!
     497             : //!   rt.release(fn);                   // Remove the function from the runtime.
     498             : //!   return 0;
     499             : //! }
     500             : //! ```
     501             : //!
     502             : //! If you run the example it will just work, because both instructions have the same size. As an experiment you can
     503             : //! try removing `long_()` form to see what happens when wrong code is generated.
     504             : //!
     505             : //! ### Code Patching and REX Prefix
     506             : //!
     507             : //! In 64-bit mode there is one more thing to worry about when patching code: REX prefix. It's a single byte prefix
     508             : //! designed to address registers with ids from 9 to 15 and to override the default width of operation from 32 to 64
     509             : //! bits. AsmJit, like other assemblers, only emits REX prefix when it's necessary. If the patched code only changes
     510             : //! the immediate value as shown in the previous example then there is nothing to worry about as it doesn't change
     511             : //! the logic behind emitting REX prefix, however, if the patched code changes register id or overrides the operation
     512             : //! width then it's important to take care of REX prefix as well.
     513             : //!
     514             : //! AsmJit contains another instruction option that controls (forces) REX prefix - `rex()`. If you use it the
     515             : //! instruction emitted will always use REX prefix even when it's encodable without it. The following list contains
     516             : //! some instructions and their binary representations to illustrate when it's emitted:
     517             : //!
     518             : //!   - `__83C410` - `add esp, 16`     - 32-bit operation in 64-bit mode doesn't require REX prefix.
     519             : //!   - `4083C410` - `rex add esp, 16` - 32-bit operation in 64-bit mode with forced REX prefix (0x40).
     520             : //!   - `4883C410` - `add rsp, 16`     - 64-bit operation in 64-bit mode requires REX prefix (0x48).
     521             : //!   - `4183C410` - `add r12d, 16`    - 32-bit operation in 64-bit mode using R12D requires REX prefix (0x41).
     522             : //!   - `4983C410` - `add r12, 16`     - 64-bit operation in 64-bit mode using R12 requires REX prefix (0x49).
     523             : //!
     524             : //! ### More Prefixes
     525             : //!
     526             : //! X86 architecture is known for its prefixes. AsmJit supports all prefixes
     527             : //! that can affect how the instruction is encoded:
     528             : //!
     529             : //! ```
     530             : //! #include <asmjit/x86.h>
     531             : //!
     532             : //! using namespace asmjit;
     533             : //!
     534             : //! void prefixesExample(x86::Assembler& a) {
     535             : //!   // Lock prefix for implementing atomics:
     536             : //!   //   lock add dword ptr [dst], 1
     537             : //!   a.lock().add(x86::dword_ptr(dst), 1);
     538             : //!
     539             : //!   // Similarly, XAcquire/XRelease prefixes are also available:
     540             : //!   //   xacquire add dword ptr [dst], 1
     541             : //!   a.xacquire().add(x86::dword_ptr(dst), 1);
     542             : //!
     543             : //!   // Rep prefix (see also repe/repz and repne/repnz):
     544             : //!   //   rep movs byte ptr [dst], byte ptr [src]
     545             : //!   a.rep().movs(x86::byte_ptr(dst), x86::byte_ptr(src));
     546             : //!
     547             : //!   // Forcing REX prefix in 64-bit mode.
     548             : //!   //   rex mov eax, 1
     549             : //!   a.rex().mov(x86::eax, 1);
     550             : //!
     551             : //!   // AVX instruction without forced prefix uses the shortest encoding:
     552             : //!   //   vaddpd xmm0, xmm1, xmm2 -> [C5|F1|58|C2]
     553             : //!   a.vaddpd(x86::xmm0, x86::xmm1, x86::xmm2);
     554             : //!
     555             : //!   // Forcing VEX3 prefix (AVX):
     556             : //!   //   vex3 vaddpd xmm0, xmm1, xmm2 -> [C4|E1|71|58|C2]
     557             : //!   a.vex3().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2);
     558             : //!
     559             : //!   // Forcing EVEX prefix (AVX512):
     560             : //!   //   evex vaddpd xmm0, xmm1, xmm2 -> [62|F1|F5|08|58|C2]
     561             : //!   a.evex().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2);
     562             : //!
     563             : //!   // Some instructions accept prefixes not originally intended to:
     564             : //!   //   rep ret
     565             : //!   a.rep().ret();
     566             : //! }
     567             : //! ```
     568             : //!
     569             : //! It's important to understand that prefixes are part of instruction options. When a member function that involves
     570             : //! adding a prefix is called the prefix is combined with existing instruction options, which will affect the next
     571             : //! instruction generated.
     572             : //!
     573             : //! ### Generating AVX512 code.
     574             : //!
     575             : //! x86::Assembler can generate AVX512+ code including the use of opmask registers. Opmask can be specified through
     576             : //! \ref x86::Assembler::k() function, which stores it as an extra register, which will be used by the next
     577             : //! instruction. AsmJit uses such concept for manipulating instruction options as well.
     578             : //!
     579             : //! The following AVX512 features are supported:
     580             : //!
     581             : //!   - Opmask selector {k} and zeroing {z}.
     582             : //!   - Rounding modes {rn|rd|ru|rz} and suppress-all-exceptions {sae} option.
     583             : //!   - AVX512 broadcasts {1toN}.
     584             : //!
     585             : //! The following example demonstrates how AVX512 features can be used:
     586             : //!
     587             : //! ```
     588             : //! #include <asmjit/x86.h>
     589             : //!
     590             : //! using namespace asmjit;
     591             : //!
     592             : //! void generateAVX512Code(x86::Assembler& a) {
     593             : //!   using namespace x86;
     594             : //!
     595             : //!   // Opmask Selectors
     596             : //!   // ----------------
     597             : //!   //
     598             : //!   //   - Opmask / zeroing is part of the instruction options / extraReg.
     599             : //!   //   - k(reg) is like {kreg} in Intel syntax.
     600             : //!   //   - z() is like {z} in Intel syntax.
     601             : //!
     602             : //!   // vaddpd zmm {k1} {z}, zmm1, zmm2
     603             : //!   a.k(k1).z().vaddpd(zmm0, zmm1, zmm2);
     604             : //!
     605             : //!   // Memory Broadcasts
     606             : //!   // -----------------
     607             : //!   //
     608             : //!   //   - Broadcast data is part of memory operand.
     609             : //!   //   - Use x86::Mem::_1toN(), which returns a new x86::Mem operand.
     610             : //!
     611             : //!   // vaddpd zmm0 {k1} {z}, zmm1, [rcx] {1to8}
     612             : //!   a.k(k1).z().vaddpd(zmm0, zmm1, x86::mem(rcx)._1to8());
     613             : //!
     614             : //!   // Embedded Rounding & Suppress-All-Exceptoins
     615             : //!   // -------------------------------------------
     616             : //!   //
     617             : //!   //   - Rounding mode and {sae} are part of instruction options.
     618             : //!   //   - Use sae() to enable exception suppression.
     619             : //!   //   - Use rn_sae(), rd_sae(), ru_sae(), and rz_sae() - to enable rounding.
     620             : //!   //   - Embedded rounding implicitly sets {sae} as well, that's why the API
     621             : //!   //     also has sae() suffix, to make it clear.
     622             : //!
     623             : //!   // vcmppd k1, zmm1, zmm2, 0x00 {sae}
     624             : //!   a.sae().vcmppd(k1, zmm1, zmm2, 0);
     625             : //!
     626             : //!   // vaddpd zmm0, zmm1, zmm2 {rz}
     627             : //!   a.rz_sae().vaddpd(zmm0, zmm1, zmm2);
     628             : //! }
     629             : //! ```
     630             : class ASMJIT_VIRTAPI Assembler
     631             :   : public BaseAssembler,
     632             :     public EmitterImplicitT<Assembler> {
     633             : public:
     634             :   ASMJIT_NONCOPYABLE(Assembler)
     635             :   typedef BaseAssembler Base;
     636             : 
     637             :   //! \name Construction & Destruction
     638             :   //! \{
     639             : 
     640             :   ASMJIT_API explicit Assembler(CodeHolder* code = nullptr) noexcept;
     641             :   ASMJIT_API virtual ~Assembler() noexcept;
     642             : 
     643             :   //! \}
     644             : 
     645             :   //! \cond INTERNAL
     646             :   //! \name Internal
     647             :   //! \{
     648             : 
     649             :   // NOTE: x86::Assembler uses _privateData to store 'address-override' bit that is used to decide whether to emit
     650             :   // address-override (67H) prefix based on the memory BASE+INDEX registers. It's either `kX86MemInfo_67H_X86` or
     651             :   // `kX86MemInfo_67H_X64`.
     652      142105 :   inline uint32_t _addressOverrideMask() const noexcept { return _privateData; }
     653       27492 :   inline void _setAddressOverrideMask(uint32_t m) noexcept { _privateData = m; }
     654             : 
     655             :   //! \}
     656             :   //! \endcond
     657             : 
     658             :   //! \name Emit
     659             :   //! \{
     660             : 
     661             :   ASMJIT_API Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override;
     662             : 
     663             :   //! \}
     664             :   //! \endcond
     665             : 
     666             :   //! \name Align
     667             :   //! \{
     668             : 
     669             :   ASMJIT_API Error align(AlignMode alignMode, uint32_t alignment) override;
     670             : 
     671             :   //! \}
     672             : 
     673             :   //! \name Events
     674             :   //! \{
     675             : 
     676             :   ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
     677             :   ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
     678             : 
     679             :   //! \}
     680             : };
     681             : 
     682             : //! \}
     683             : 
     684             : ASMJIT_END_SUB_NAMESPACE
     685             : 
     686             : #endif // ASMJIT_X86_X86ASSEMBLER_H_INCLUDED
     687             : 
     688             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16