1 // AsmJit - Machine code generation for C++
2 //
3 //  * Official AsmJit Home Page: https://asmjit.com
4 //  * Official Github Repository: https://github.com/asmjit/asmjit
5 //
6 // Copyright (c) 2008-2020 The AsmJit Authors
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 //    claim that you wrote the original software. If you use this software
18 //    in a product, an acknowledgment in the product documentation would be
19 //    appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not be
21 //    misrepresented as being the original software.
22 // 3. This notice may not be removed or altered from any source distribution.
23 
24 #ifndef ASMJIT_X86_X86COMPILER_H_INCLUDED
25 #define ASMJIT_X86_X86COMPILER_H_INCLUDED
26 
27 #include "../core/api-config.h"
28 #ifndef ASMJIT_NO_COMPILER
29 
30 #include "../core/compiler.h"
31 #include "../core/datatypes.h"
32 #include "../core/type.h"
33 #include "../x86/x86emitter.h"
34 
ASMJIT_BEGIN_SUB_NAMESPACE(x86)35 ASMJIT_BEGIN_SUB_NAMESPACE(x86)
36 
37 //! \addtogroup asmjit_x86
38 //! \{
39 
40 // ============================================================================
41 // [asmjit::x86::Compiler]
42 // ============================================================================
43 
44 //! X86/X64 compiler implementation.
45 //!
46 //! ### Compiler Basics
47 //!
48 //! The first \ref x86::Compiler example shows how to generate a function that
49 //! simply returns an integer value. It's an analogy to the first Assembler example:
50 //!
51 //! ```
52 //! #include <asmjit/x86.h>
53 //! #include <stdio.h>
54 //!
55 //! using namespace asmjit;
56 //!
57 //! // Signature of the generated function.
58 //! typedef int (*Func)(void);
59 //!
60 //! int main() {
61 //!   JitRuntime rt;                    // Runtime specialized for JIT code execution.
62 //!   CodeHolder code;                  // Holds code and relocation information.
63 //!
64 //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
65 //!   x86::Compiler cc(&code);          // Create and attach x86::Compiler to code.
66 //!
67 //!   cc.addFunc(FuncSignatureT<int>());// Begin a function of `int fn(void)` signature.
68 //!
69 //!   x86::Gp vReg = cc.newGpd();       // Create a 32-bit general purpose register.
70 //!   cc.mov(vReg, 1);                  // Move one to our virtual register `vReg`.
71 //!   cc.ret(vReg);                     // Return `vReg` from the function.
72 //!
73 //!   cc.endFunc();                     // End of the function body.
74 //!   cc.finalize();                    // Translate and assemble the whole 'cc' content.
75 //!   // ----> x86::Compiler is no longer needed from here and can be destroyed <----
76 //!
77 //!   Func fn;
78 //!   Error err = rt.add(&fn, &code);   // Add the generated code to the runtime.
79 //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
80 //!   // ----> CodeHolder is no longer needed from here and can be destroyed <----
81 //!
82 //!   int result = fn();                // Execute the generated code.
83 //!   printf("%d\n", result);           // Print the resulting "1".
84 //!
85 //!   rt.release(fn);                   // Explicitly remove the function from the runtime.
86 //!   return 0;
87 //! }
88 //! ```
89 //!
90 //! The \ref BaseCompiler::addFunc() and \ref BaseCompiler::endFunc() functions
91 //! are used to define the function and its end. Both must be called per function,
92 //! but the body doesn't have to be generated in sequence. An example of generating
93 //! two functions will be shown later. The next example shows more complicated code
94 //! that contain a loop and generates a simple memory copy function that uses
95 //! `uint32_t` items:
96 //!
97 //! ```
98 //! #include <asmjit/x86.h>
99 //! #include <stdio.h>
100 //!
101 //! using namespace asmjit;
102 //!
103 //! // Signature of the generated function.
104 //! typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count);
105 //!
106 //! int main() {
107 //!   JitRuntime rt;                    // Runtime specialized for JIT code execution.
108 //!   CodeHolder code;                  // Holds code and relocation information.
109 //!
110 //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
111 //!   x86::Compiler cc(&code);          // Create and attach x86::Compiler to code.
112 //!
113 //!   cc.addFunc(                       // Begin the function of the following signature:
114 //!     FuncSignatureT<void,            //   Return value - void      (no return value).
115 //!       uint32_t*,                    //   1st argument - uint32_t* (machine reg-size).
116 //!       const uint32_t*,              //   2nd argument - uint32_t* (machine reg-size).
117 //!       size_t>());                   //   3rd argument - size_t    (machine reg-size).
118 //!
119 //!   Label L_Loop = cc.newLabel();     // Start of the loop.
120 //!   Label L_Exit = cc.newLabel();     // Used to exit early.
121 //!
122 //!   x86::Gp dst = cc.newIntPtr("dst");// Create `dst` register (destination pointer).
123 //!   x86::Gp src = cc.newIntPtr("src");// Create `src` register (source pointer).
124 //!   x86::Gp i = cc.newUIntPtr("i");   // Create `i` register (loop counter).
125 //!
126 //!   cc.setArg(0, dst);                // Assign `dst` argument.
127 //!   cc.setArg(1, src);                // Assign `src` argument.
128 //!   cc.setArg(2, i);                  // Assign `i` argument.
129 //!
130 //!   cc.test(i, i);                    // Early exit if length is zero.
131 //!   cc.jz(L_Exit);
132 //!
133 //!   cc.bind(L_Loop);                  // Bind the beginning of the loop here.
134 //!
135 //!   x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes).
136 //!   cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address.
137 //!   cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address.
138 //!
139 //!   cc.add(src, 4);                   // Increment `src`.
140 //!   cc.add(dst, 4);                   // Increment `dst`.
141 //!
142 //!   cc.dec(i);                        // Loop until `i` is non-zero.
143 //!   cc.jnz(L_Loop);
144 //!
145 //!   cc.bind(L_Exit);                  // Label used by early exit.
146 //!   cc.endFunc();                     // End of the function body.
147 //!
148 //!   cc.finalize();                    // Translate and assemble the whole 'cc' content.
149 //!   // ----> x86::Compiler is no longer needed from here and can be destroyed <----
150 //!
151 //!   // Add the generated code to the runtime.
152 //!   MemCpy32 memcpy32;
153 //!   Error err = rt.add(&memcpy32, &code);
154 //!
155 //!   // Handle a possible error returned by AsmJit.
156 //!   if (err)
157 //!     return 1;
158 //!   // ----> CodeHolder is no longer needed from here and can be destroyed <----
159 //!
160 //!   // Test the generated code.
161 //!   uint32_t input[6] = { 1, 2, 3, 5, 8, 13 };
162 //!   uint32_t output[6];
163 //!   memcpy32(output, input, 6);
164 //!
165 //!   for (uint32_t i = 0; i < 6; i++)
166 //!     printf("%d\n", output[i]);
167 //!
168 //!   rt.release(memcpy32);
169 //!   return 0;
170 //! }
171 //! ```
172 //!
173 //! ### Recursive Functions
174 //!
175 //! It's possible to create more functions by using the same \ref x86::Compiler
176 //! instance and make links between them. In such case it's important to keep
177 //! the pointer to \ref FuncNode.
178 //!
179 //! The example below creates a simple Fibonacci function that calls itself recursively:
180 //!
181 //! ```
182 //! #include <asmjit/x86.h>
183 //! #include <stdio.h>
184 //!
185 //! using namespace asmjit;
186 //!
187 //! // Signature of the generated function.
188 //! typedef uint32_t (*Fibonacci)(uint32_t x);
189 //!
190 //! int main() {
191 //!   JitRuntime rt;                    // Runtime specialized for JIT code execution.
192 //!   CodeHolder code;                  // Holds code and relocation information.
193 //!
194 //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
195 //!   x86::Compiler cc(&code);          // Create and attach x86::Compiler to code.
196 //!
197 //!   FuncNode* func = cc.addFunc(      // Begin of the Fibonacci function, addFunc()
198 //!     FuncSignatureT<int, int>());    // Returns a pointer to the FuncNode node.
199 //!
200 //!   Label L_Exit = cc.newLabel()      // Exit label.
201 //!   x86::Gp x = cc.newU32();          // Function x argument.
202 //!   x86::Gp y = cc.newU32();          // Temporary.
203 //!
204 //!   cc.setArg(0, x);
205 //!
206 //!   cc.cmp(x, 3);                     // Return x if less than 3.
207 //!   cc.jb(L_Exit);
208 //!
209 //!   cc.mov(y, x);                     // Make copy of the original x.
210 //!   cc.dec(x);                        // Decrease x.
211 //!
212 //!   InvokeNode* invokeNode;           // Function invocation:
213 //!   cc.invoke(&invokeNode,            //   - InvokeNode (output).
214 //!     func->label(),                  //   - Function address or Label.
215 //!     FuncSignatureT<int, int>());    //   - Function signature.
216 //!
217 //!   invokeNode->setArg(0, x);         // Assign x as the first argument.
218 //!   invokeNode->setRet(0, x);         // Assign x as a return value as well.
219 //!
220 //!   cc.add(x, y);                     // Combine the return value with y.
221 //!
222 //!   cc.bind(L_Exit);
223 //!   cc.ret(x);                        // Return x.
224 //!   cc.endFunc();                     // End of the function body.
225 //!
226 //!   cc.finalize();                    // Translate and assemble the whole 'cc' content.
227 //!   // ----> x86::Compiler is no longer needed from here and can be destroyed <----
228 //!
229 //!   Fibonacci fib;
230 //!   Error err = rt.add(&fib, &code);  // Add the generated code to the runtime.
231 //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
232 //!   // ----> CodeHolder is no longer needed from here and can be destroyed <----
233 //!
234 //!   // Test the generated code.
235 //!   printf("Fib(%u) -> %u\n", 8, fib(8));
236 //!
237 //!   rt.release(fib);
238 //!   return 0;
239 //! }
240 //! ```
241 //!
242 //! ### Stack Management
243 //!
244 //! 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.
245 //!
246 //! ```
247 //! #include <asmjit/x86.h>
248 //! #include <stdio.h>
249 //!
250 //! using namespace asmjit;
251 //!
252 //! // Signature of the generated function.
253 //! typedef int (*Func)(void);
254 //!
255 //! int main() {
256 //!   JitRuntime rt;                    // Runtime specialized for JIT code execution.
257 //!   CodeHolder code;                  // Holds code and relocation information.
258 //!
259 //!   code.init(rt.environment());      // Initialize code to match the JIT environment.
260 //!   x86::Compiler cc(&code);          // Create and attach x86::Compiler to code.
261 //!
262 //!   cc.addFunc(FuncSignatureT<int>());// Create a function that returns int.
263 //!
264 //!   x86::Gp p = cc.newIntPtr("p");
265 //!   x86::Gp i = cc.newIntPtr("i");
266 //!
267 //!   // Allocate 256 bytes on the stack aligned to 4 bytes.
268 //!   x86::Mem stack = cc.newStack(256, 4);
269 //!
270 //!   x86::Mem stackIdx(stack);         // Copy of stack with i added.
271 //!   stackIdx.setIndex(i);             // stackIdx <- stack[i].
272 //!   stackIdx.setSize(1);              // stackIdx <- byte ptr stack[i].
273 //!
274 //!   // Load a stack address to `p`. This step is purely optional and shows
275 //!   // that `lea` is useful to load a memory operands address (even absolute)
276 //!   // to a general purpose register.
277 //!   cc.lea(p, stack);
278 //!
279 //!   // Clear i (xor is a C++ keyword, hence 'xor_' is used instead).
280 //!   cc.xor_(i, i);
281 //!
282 //!   Label L1 = cc.newLabel();
283 //!   Label L2 = cc.newLabel();
284 //!
285 //!   cc.bind(L1);                      // First loop, fill the stack.
286 //!   cc.mov(stackIdx, i.r8());         // stack[i] = uint8_t(i).
287 //!
288 //!   cc.inc(i);                        // i++;
289 //!   cc.cmp(i, 256);                   // if (i < 256)
290 //!   cc.jb(L1);                        //   goto L1;
291 //!
292 //!   // Second loop, sum all bytes stored in `stack`.
293 //!   x86::Gp sum = cc.newI32("sum");
294 //!   x86::Gp val = cc.newI32("val");
295 //!
296 //!   cc.xor_(i, i);
297 //!   cc.xor_(sum, sum);
298 //!
299 //!   cc.bind(L2);
300 //!
301 //!   cc.movzx(val, stackIdx);          // val = uint32_t(stack[i]);
302 //!   cc.add(sum, val);                 // sum += val;
303 //!
304 //!   cc.inc(i);                        // i++;
305 //!   cc.cmp(i, 256);                   // if (i < 256)
306 //!   cc.jb(L2);                        //   goto L2;
307 //!
308 //!   cc.ret(sum);                      // Return the `sum` of all values.
309 //!   cc.endFunc();                     // End of the function body.
310 //!
311 //!   cc.finalize();                    // Translate and assemble the whole 'cc' content.
312 //!   // ----> x86::Compiler is no longer needed from here and can be destroyed <----
313 //!
314 //!   Func func;
315 //!   Error err = rt.add(&func, &code); // Add the generated code to the runtime.
316 //!   if (err) return 1;                // Handle a possible error returned by AsmJit.
317 //!   // ----> CodeHolder is no longer needed from here and can be destroyed <----
318 //!
319 //!   printf("Func() -> %d\n", func()); // Test the generated code.
320 //!
321 //!   rt.release(func);
322 //!   return 0;
323 //! }
324 //! ```
325 //!
326 //! ### Constant Pool
327 //!
328 //! Compiler provides two constant pools for a general purpose code generation:
329 //!
330 //!   - Local constant pool - Part of \ref FuncNode, can be only used by a
331 //!     single function and added after the function epilog sequence (after
332 //!     `ret` instruction).
333 //!
334 //!   - Global constant pool - Part of \ref BaseCompiler, flushed at the end
335 //!     of the generated code by \ref BaseEmitter::finalize().
336 //!
337 //! The example below illustrates how a built-in constant pool can be used:
338 //!
339 //! ```
340 //! #include <asmjit/x86.h>
341 //!
342 //! using namespace asmjit;
343 //!
344 //! static void exampleUseOfConstPool(x86::Compiler& cc) {
345 //!   cc.addFunc(FuncSignatureT<int>());
346 //!
347 //!   x86::Gp v0 = cc.newGpd("v0");
348 //!   x86::Gp v1 = cc.newGpd("v1");
349 //!
350 //!   x86::Mem c0 = cc.newInt32Const(ConstPool::kScopeLocal, 200);
351 //!   x86::Mem c1 = cc.newInt32Const(ConstPool::kScopeLocal, 33);
352 //!
353 //!   cc.mov(v0, c0);
354 //!   cc.mov(v1, c1);
355 //!   cc.add(v0, v1);
356 //!
357 //!   cc.ret(v0);
358 //!   cc.endFunc();
359 //! }
360 //! ```
361 //!
362 //! ### Jump Tables
363 //!
364 //! x86::Compiler supports `jmp` instruction with reg/mem operand, which is a
365 //! commonly used pattern to implement indirect jumps within a function, for
366 //! example to implement `switch()` statement in a programming languages. By
367 //! default AsmJit assumes that every basic block can be a possible jump
368 //! target as it's unable to deduce targets from instruction's operands. This
369 //! is a very pessimistic default that should be avoided if possible as it's
370 //! costly and very unfriendly to liveness analysis and register allocation.
371 //!
372 //! Instead of relying on such pessimistic default behavior, let's use \ref
373 //! JumpAnnotation to annotate a jump where all targets are known:
374 //!
375 //! ```
376 //! #include <asmjit/x86.h>
377 //!
378 //! using namespace asmjit;
379 //!
380 //! static void exampleUseOfIndirectJump(x86::Compiler& cc) {
381 //!   cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost));
382 //!
383 //!   // Function arguments
384 //!   x86::Xmm a = cc.newXmmSs("a");
385 //!   x86::Xmm b = cc.newXmmSs("b");
386 //!   x86::Gp op = cc.newUInt32("op");
387 //!
388 //!   x86::Gp target = cc.newIntPtr("target");
389 //!   x86::Gp offset = cc.newIntPtr("offset");
390 //!
391 //!   Label L_Table = cc.newLabel();
392 //!   Label L_Add = cc.newLabel();
393 //!   Label L_Sub = cc.newLabel();
394 //!   Label L_Mul = cc.newLabel();
395 //!   Label L_Div = cc.newLabel();
396 //!   Label L_End = cc.newLabel();
397 //!
398 //!   cc.setArg(0, a);
399 //!   cc.setArg(1, b);
400 //!   cc.setArg(2, op);
401 //!
402 //!   // Jump annotation is a building block that allows to annotate all
403 //!   // possible targets where `jmp()` can jump. It then drives the CFG
404 //!   // contruction and liveness analysis, which impacts register allocation.
405 //!   JumpAnnotation* annotation = cc.newJumpAnnotation();
406 //!   annotation->addLabel(L_Add);
407 //!   annotation->addLabel(L_Sub);
408 //!   annotation->addLabel(L_Mul);
409 //!   annotation->addLabel(L_Div);
410 //!
411 //!   // Most likely not the common indirect jump approach, but it
412 //!   // doesn't really matter how final address is calculated. The
413 //!   // most important path using JumpAnnotation with `jmp()`.
414 //!   cc.lea(offset, x86::ptr(L_Table));
415 //!   if (cc.is64Bit())
416 //!     cc.movsxd(target, x86::dword_ptr(offset, op.cloneAs(offset), 2));
417 //!   else
418 //!     cc.mov(target, x86::dword_ptr(offset, op.cloneAs(offset), 2));
419 //!   cc.add(target, offset);
420 //!   cc.jmp(target, annotation);
421 //!
422 //!   // Acts like a switch() statement in C.
423 //!   cc.bind(L_Add);
424 //!   cc.addss(a, b);
425 //!   cc.jmp(L_End);
426 //!
427 //!   cc.bind(L_Sub);
428 //!   cc.subss(a, b);
429 //!   cc.jmp(L_End);
430 //!
431 //!   cc.bind(L_Mul);
432 //!   cc.mulss(a, b);
433 //!   cc.jmp(L_End);
434 //!
435 //!   cc.bind(L_Div);
436 //!   cc.divss(a, b);
437 //!
438 //!   cc.bind(L_End);
439 //!   cc.ret(a);
440 //!
441 //!   cc.endFunc();
442 //!
443 //!   // Relative int32_t offsets of `L_XXX - L_Table`.
444 //!   cc.bind(L_Table);
445 //!   cc.embedLabelDelta(L_Add, L_Table, 4);
446 //!   cc.embedLabelDelta(L_Sub, L_Table, 4);
447 //!   cc.embedLabelDelta(L_Mul, L_Table, 4);
448 //!   cc.embedLabelDelta(L_Div, L_Table, 4);
449 //! }
450 //! ```
451 class ASMJIT_VIRTAPI Compiler
452   : public BaseCompiler,
453     public EmitterExplicitT<Compiler> {
454 public:
455   ASMJIT_NONCOPYABLE(Compiler)
456   typedef BaseCompiler Base;
457 
458   //! \name Construction & Destruction
459   //! \{
460 
461   ASMJIT_API explicit Compiler(CodeHolder* code = nullptr) noexcept;
462   ASMJIT_API virtual ~Compiler() noexcept;
463 
464   //! \}
465 
466   //! \name Virtual Registers
467   //! \{
468 
469 #ifndef ASMJIT_NO_LOGGING
470 # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS)                         \
471     _newRegFmt(&OUT, PARAM, FORMAT, ARGS)
472 #else
473 # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS)                         \
474     DebugUtils::unused(FORMAT);                                               \
475     DebugUtils::unused(std::forward<Args>(args)...);                          \
476     _newReg(&OUT, PARAM)
477 #endif
478 
479 #define ASMJIT_NEW_REG_CUSTOM(FUNC, REG)                                      \
480     inline REG FUNC(uint32_t typeId) {                                        \
481       REG reg(Globals::NoInit);                                               \
482       _newReg(&reg, typeId);                                                  \
483       return reg;                                                             \
484     }                                                                         \
485                                                                               \
486     template<typename... Args>                                                \
487     inline REG FUNC(uint32_t typeId, const char* fmt, Args&&... args) {       \
488       REG reg(Globals::NoInit);                                               \
489       ASMJIT_NEW_REG_FMT(reg, typeId, fmt, std::forward<Args>(args)...);      \
490       return reg;                                                             \
491     }
492 
493 #define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID)                              \
494     inline REG FUNC() {                                                       \
495       REG reg(Globals::NoInit);                                               \
496       _newReg(&reg, TYPE_ID);                                                 \
497       return reg;                                                             \
498     }                                                                         \
499                                                                               \
500     template<typename... Args>                                                \
501     inline REG FUNC(const char* fmt, Args&&... args) {                        \
502       REG reg(Globals::NoInit);                                               \
503       ASMJIT_NEW_REG_FMT(reg, TYPE_ID, fmt, std::forward<Args>(args)...);     \
504       return reg;                                                             \
505     }
506 
507   template<typename RegT>
508   inline RegT newSimilarReg(const RegT& ref) {
509     RegT reg(Globals::NoInit);
510     _newReg(reg, ref);
511     return reg;
512   }
513 
514   template<typename RegT, typename... Args>
515   inline RegT newSimilarReg(const RegT& ref, const char* fmt, Args&&... args) {
516     RegT reg(Globals::NoInit);
517     ASMJIT_NEW_REG_FMT(reg, ref, fmt, std::forward<Args>(args)...);
518     return reg;
519   }
520 
521   ASMJIT_NEW_REG_CUSTOM(newReg    , Reg )
522   ASMJIT_NEW_REG_CUSTOM(newGp     , Gp  )
523   ASMJIT_NEW_REG_CUSTOM(newVec    , Vec )
524   ASMJIT_NEW_REG_CUSTOM(newK      , KReg)
525 
526   ASMJIT_NEW_REG_TYPED(newI8     , Gp  , Type::kIdI8     )
527   ASMJIT_NEW_REG_TYPED(newU8     , Gp  , Type::kIdU8     )
528   ASMJIT_NEW_REG_TYPED(newI16    , Gp  , Type::kIdI16    )
529   ASMJIT_NEW_REG_TYPED(newU16    , Gp  , Type::kIdU16    )
530   ASMJIT_NEW_REG_TYPED(newI32    , Gp  , Type::kIdI32    )
531   ASMJIT_NEW_REG_TYPED(newU32    , Gp  , Type::kIdU32    )
532   ASMJIT_NEW_REG_TYPED(newI64    , Gp  , Type::kIdI64    )
533   ASMJIT_NEW_REG_TYPED(newU64    , Gp  , Type::kIdU64    )
534   ASMJIT_NEW_REG_TYPED(newInt8   , Gp  , Type::kIdI8     )
535   ASMJIT_NEW_REG_TYPED(newUInt8  , Gp  , Type::kIdU8     )
536   ASMJIT_NEW_REG_TYPED(newInt16  , Gp  , Type::kIdI16    )
537   ASMJIT_NEW_REG_TYPED(newUInt16 , Gp  , Type::kIdU16    )
538   ASMJIT_NEW_REG_TYPED(newInt32  , Gp  , Type::kIdI32    )
539   ASMJIT_NEW_REG_TYPED(newUInt32 , Gp  , Type::kIdU32    )
540   ASMJIT_NEW_REG_TYPED(newInt64  , Gp  , Type::kIdI64    )
541   ASMJIT_NEW_REG_TYPED(newUInt64 , Gp  , Type::kIdU64    )
542   ASMJIT_NEW_REG_TYPED(newIntPtr , Gp  , Type::kIdIntPtr )
543   ASMJIT_NEW_REG_TYPED(newUIntPtr, Gp  , Type::kIdUIntPtr)
544 
545   ASMJIT_NEW_REG_TYPED(newGpb    , Gp  , Type::kIdU8     )
546   ASMJIT_NEW_REG_TYPED(newGpw    , Gp  , Type::kIdU16    )
547   ASMJIT_NEW_REG_TYPED(newGpd    , Gp  , Type::kIdU32    )
548   ASMJIT_NEW_REG_TYPED(newGpq    , Gp  , Type::kIdU64    )
549   ASMJIT_NEW_REG_TYPED(newGpz    , Gp  , Type::kIdUIntPtr)
550   ASMJIT_NEW_REG_TYPED(newXmm    , Xmm , Type::kIdI32x4  )
551   ASMJIT_NEW_REG_TYPED(newXmmSs  , Xmm , Type::kIdF32x1  )
552   ASMJIT_NEW_REG_TYPED(newXmmSd  , Xmm , Type::kIdF64x1  )
553   ASMJIT_NEW_REG_TYPED(newXmmPs  , Xmm , Type::kIdF32x4  )
554   ASMJIT_NEW_REG_TYPED(newXmmPd  , Xmm , Type::kIdF64x2  )
555   ASMJIT_NEW_REG_TYPED(newYmm    , Ymm , Type::kIdI32x8  )
556   ASMJIT_NEW_REG_TYPED(newYmmPs  , Ymm , Type::kIdF32x8  )
557   ASMJIT_NEW_REG_TYPED(newYmmPd  , Ymm , Type::kIdF64x4  )
558   ASMJIT_NEW_REG_TYPED(newZmm    , Zmm , Type::kIdI32x16 )
559   ASMJIT_NEW_REG_TYPED(newZmmPs  , Zmm , Type::kIdF32x16 )
560   ASMJIT_NEW_REG_TYPED(newZmmPd  , Zmm , Type::kIdF64x8  )
561   ASMJIT_NEW_REG_TYPED(newMm     , Mm  , Type::kIdMmx64  )
562   ASMJIT_NEW_REG_TYPED(newKb     , KReg, Type::kIdMask8  )
563   ASMJIT_NEW_REG_TYPED(newKw     , KReg, Type::kIdMask16 )
564   ASMJIT_NEW_REG_TYPED(newKd     , KReg, Type::kIdMask32 )
565   ASMJIT_NEW_REG_TYPED(newKq     , KReg, Type::kIdMask64 )
566 
567 #undef ASMJIT_NEW_REG_TYPED
568 #undef ASMJIT_NEW_REG_CUSTOM
569 #undef ASMJIT_NEW_REG_FMT
570 
571   //! \}
572 
573   //! \name Stack
574   //! \{
575 
576   //! Creates a new memory chunk allocated on the current function's stack.
577   inline Mem newStack(uint32_t size, uint32_t alignment, const char* name = nullptr) {
578     Mem m(Globals::NoInit);
579     _newStack(&m, size, alignment, name);
580     return m;
581   }
582 
583   //! \}
584 
585   //! \name Constants
586   //! \{
587 
588   //! Put data to a constant-pool and get a memory reference to it.
589   inline Mem newConst(uint32_t scope, const void* data, size_t size) {
590     Mem m(Globals::NoInit);
591     _newConst(&m, scope, data, size);
592     return m;
593   }
594 
595   //! Put a BYTE `val` to a constant-pool.
596   inline Mem newByteConst(uint32_t scope, uint8_t val) noexcept { return newConst(scope, &val, 1); }
597   //! Put a WORD `val` to a constant-pool.
598   inline Mem newWordConst(uint32_t scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
599   //! Put a DWORD `val` to a constant-pool.
600   inline Mem newDWordConst(uint32_t scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
601   //! Put a QWORD `val` to a constant-pool.
602   inline Mem newQWordConst(uint32_t scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
603 
604   //! Put a WORD `val` to a constant-pool.
605   inline Mem newInt16Const(uint32_t scope, int16_t val) noexcept { return newConst(scope, &val, 2); }
606   //! Put a WORD `val` to a constant-pool.
607   inline Mem newUInt16Const(uint32_t scope, uint16_t val) noexcept { return newConst(scope, &val, 2); }
608   //! Put a DWORD `val` to a constant-pool.
609   inline Mem newInt32Const(uint32_t scope, int32_t val) noexcept { return newConst(scope, &val, 4); }
610   //! Put a DWORD `val` to a constant-pool.
611   inline Mem newUInt32Const(uint32_t scope, uint32_t val) noexcept { return newConst(scope, &val, 4); }
612   //! Put a QWORD `val` to a constant-pool.
613   inline Mem newInt64Const(uint32_t scope, int64_t val) noexcept { return newConst(scope, &val, 8); }
614   //! Put a QWORD `val` to a constant-pool.
615   inline Mem newUInt64Const(uint32_t scope, uint64_t val) noexcept { return newConst(scope, &val, 8); }
616 
617   //! Put a SP-FP `val` to a constant-pool.
618   inline Mem newFloatConst(uint32_t scope, float val) noexcept { return newConst(scope, &val, 4); }
619   //! Put a DP-FP `val` to a constant-pool.
620   inline Mem newDoubleConst(uint32_t scope, double val) noexcept { return newConst(scope, &val, 8); }
621 
622 #ifndef ASMJIT_NO_DEPRECATED
623   ASMJIT_DEPRECATED("newMmConst() uses a deprecated Data64, use newConst() with your own data instead")
624   inline Mem newMmConst(uint32_t scope, const Data64& val) noexcept { return newConst(scope, &val, 8); }
625 
626   ASMJIT_DEPRECATED("newXmmConst() uses a deprecated Data128, use newConst() with your own data instead")
627   inline Mem newXmmConst(uint32_t scope, const Data128& val) noexcept { return newConst(scope, &val, 16); }
628 
629   ASMJIT_DEPRECATED("newYmmConst() uses a deprecated Data256, use newConst() with your own data instead")
630   inline Mem newYmmConst(uint32_t scope, const Data256& val) noexcept { return newConst(scope, &val, 32); }
631 #endif // !ASMJIT_NO_DEPRECATED
632 
633   //! \}
634 
635   //! \name Instruction Options
636   //! \{
637 
638   //! Force the compiler to not follow the conditional or unconditional jump.
639   inline Compiler& unfollow() noexcept { _instOptions |= Inst::kOptionUnfollow; return *this; }
640   //! Tell the compiler that the destination variable will be overwritten.
641   inline Compiler& overwrite() noexcept { _instOptions |= Inst::kOptionOverwrite; return *this; }
642 
643   //! \}
644 
645   //! \name Function Call & Ret Intrinsics
646   //! \{
647 
648   //! Invoke a function call without `target` type enforcement.
649   inline Error invoke_(InvokeNode** out, const Operand_& target, const FuncSignature& signature) {
650     return _addInvokeNode(out, Inst::kIdCall, target, signature);
651   }
652 
653   //! Invoke a function call of the given `target` and `signature` and store
654   //! the added node to `out`.
655   //!
656   //! Creates a new \ref InvokeNode, initializes all the necessary members to
657   //! match the given function `signature`, adds the node to the compiler, and
658   //! stores its pointer to `out`. The operation is atomic, if anything fails
659   //! nullptr is stored in `out` and error code is returned.
660   inline Error invoke(InvokeNode** out, const Gp& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
661   //! \overload
662   inline Error invoke(InvokeNode** out, const Mem& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
663   //! \overload
664   inline Error invoke(InvokeNode** out, const Label& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
665   //! \overload
666   inline Error invoke(InvokeNode** out, const Imm& target, const FuncSignature& signature) { return invoke_(out, target, signature); }
667   //! \overload
668   inline Error invoke(InvokeNode** out, uint64_t target, const FuncSignature& signature) { return invoke_(out, Imm(int64_t(target)), signature); }
669 
670 #ifndef _DOXYGEN
671   template<typename Target>
672   ASMJIT_DEPRECATED("Use invoke() instead of call()")
673   inline InvokeNode* call(const Target& target, const FuncSignature& signature) {
674     InvokeNode* invokeNode;
675     invoke(&invokeNode, target, signature);
676     return invokeNode;
677   }
678 #endif
679 
680   //! Return.
681   inline FuncRetNode* ret() { return addRet(Operand(), Operand()); }
682   //! \overload
683   inline FuncRetNode* ret(const BaseReg& o0) { return addRet(o0, Operand()); }
684   //! \overload
685   inline FuncRetNode* ret(const BaseReg& o0, const BaseReg& o1) { return addRet(o0, o1); }
686 
687   //! \}
688 
689   //! \name Jump Tables Support
690   //! \{
691 
692   using EmitterExplicitT<Compiler>::jmp;
693 
694   //! Adds a jump to the given `target` with the provided jump `annotation`.
695   inline Error jmp(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
696   //! \overload
697   inline Error jmp(const BaseMem& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); }
698 
699   //! \}
700 
701   //! \name Finalize
702   //! \{
703 
704   ASMJIT_API Error finalize() override;
705 
706   //! \}
707 
708   //! \name Events
709   //! \{
710 
711   ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
712 
713   //! \}
714 };
715 
716 //! \}
717 
718 ASMJIT_END_SUB_NAMESPACE
719 
720 #endif // !ASMJIT_NO_COMPILER
721 #endif // ASMJIT_X86_X86COMPILER_H_INCLUDED
722