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_CORE_COMPILER_H_INCLUDED
25 #define ASMJIT_CORE_COMPILER_H_INCLUDED
26 
27 #include "../core/api-config.h"
28 #ifndef ASMJIT_NO_COMPILER
29 
30 #include "../core/assembler.h"
31 #include "../core/builder.h"
32 #include "../core/constpool.h"
33 #include "../core/compilerdefs.h"
34 #include "../core/func.h"
35 #include "../core/inst.h"
36 #include "../core/operand.h"
37 #include "../core/support.h"
38 #include "../core/zone.h"
39 #include "../core/zonevector.h"
40 
41 ASMJIT_BEGIN_NAMESPACE
42 
43 // ============================================================================
44 // [Forward Declarations]
45 // ============================================================================
46 
47 class JumpAnnotation;
48 class JumpNode;
49 class FuncNode;
50 class FuncRetNode;
51 class InvokeNode;
52 
53 //! \addtogroup asmjit_compiler
54 //! \{
55 
56 // ============================================================================
57 // [asmjit::BaseCompiler]
58 // ============================================================================
59 
60 //! Code emitter that uses virtual registers and performs register allocation.
61 //!
62 //! Compiler is a high-level code-generation tool that provides register
63 //! allocation and automatic handling of function calling conventions. It was
64 //! primarily designed for merging multiple parts of code into a function
65 //! without worrying about registers and function calling conventions.
66 //!
67 //! BaseCompiler can be used, with a minimum effort, to handle 32-bit and
68 //! 64-bit code generation within a single code base.
69 //!
70 //! BaseCompiler is based on BaseBuilder and contains all the features it
71 //! provides. It means that the code it stores can be modified (removed, added,
72 //! injected) and analyzed. When the code is finalized the compiler can emit
73 //! the code into an Assembler to translate the abstract representation into a
74 //! machine code.
75 //!
76 //! Check out architecture specific compilers for more details and examples:
77 //!
78 //!   - \ref x86::Compiler - X86/X64 compiler implementation.
79 class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder {
80 public:
81   ASMJIT_NONCOPYABLE(BaseCompiler)
82   typedef BaseBuilder Base;
83 
84   //! Current function.
85   FuncNode* _func;
86   //! Allocates `VirtReg` objects.
87   Zone _vRegZone;
88   //! Stores array of `VirtReg` pointers.
89   ZoneVector<VirtReg*> _vRegArray;
90   //! Stores jump annotations.
91   ZoneVector<JumpAnnotation*> _jumpAnnotations;
92 
93   //! Local constant pool, flushed at the end of each function.
94   ConstPoolNode* _localConstPool;
95   //! Global constant pool, flushed by `finalize()`.
96   ConstPoolNode* _globalConstPool;
97 
98   //! \name Construction & Destruction
99   //! \{
100 
101   //! Creates a new `BaseCompiler` instance.
102   ASMJIT_API BaseCompiler() noexcept;
103   //! Destroys the `BaseCompiler` instance.
104   ASMJIT_API virtual ~BaseCompiler() noexcept;
105 
106   //! \}
107 
108   //! \name Function Management
109   //! \{
110 
111   //! Returns the current function.
func()112   inline FuncNode* func() const noexcept { return _func; }
113 
114   //! Creates a new \ref FuncNode.
115   ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature);
116   //! Creates a new \ref FuncNode adds it to the compiler.
117   ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature);
118 
119   //! Creates a new \ref FuncRetNode.
120   ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
121   //! Creates a new \ref FuncRetNode and adds it to the compiler.
122   ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
123 
124   //! Creates a new \ref FuncNode with the given `signature` and returns it.
newFunc(const FuncSignature & signature)125   inline FuncNode* newFunc(const FuncSignature& signature) {
126     FuncNode* node;
127     _newFuncNode(&node, signature);
128     return node;
129   }
130 
131   //! Creates a new \ref FuncNode with the given `signature`, adds it to the
132   //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it.
addFunc(const FuncSignature & signature)133   inline FuncNode* addFunc(const FuncSignature& signature) {
134     FuncNode* node;
135     _addFuncNode(&node, signature);
136     return node;
137   }
138 
139   //! Adds a function `node` to the instruction stream.
140   ASMJIT_API FuncNode* addFunc(FuncNode* func);
141   //! Emits a sentinel that marks the end of the current function.
142   ASMJIT_API Error endFunc();
143 
144   ASMJIT_API Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg);
145 
146   //! Sets a function argument at `argIndex` to `reg`.
setArg(size_t argIndex,const BaseReg & reg)147   inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); }
148   //! Sets a function argument at `argIndex` at `valueIndex` to `reg`.
setArg(size_t argIndex,size_t valueIndex,const BaseReg & reg)149   inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); }
150 
newRet(const Operand_ & o0,const Operand_ & o1)151   inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) {
152     FuncRetNode* node;
153     _newRetNode(&node, o0, o1);
154     return node;
155   }
156 
addRet(const Operand_ & o0,const Operand_ & o1)157   inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) {
158     FuncRetNode* node;
159     _addRetNode(&node, o0, o1);
160     return node;
161   }
162 
163   //! \}
164 
165   //! \name Function Invocation
166   //! \{
167 
168   //! Creates a new \ref InvokeNode.
169   ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
170   //! Creates a new \ref InvokeNode and adds it to Compiler.
171   ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
172 
173   //! Creates a new `InvokeNode`.
newCall(uint32_t instId,const Operand_ & o0,const FuncSignature & signature)174   inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
175     InvokeNode* node;
176     _newInvokeNode(&node, instId, o0, signature);
177     return node;
178   }
179 
180   //! Adds a new `InvokeNode`.
addCall(uint32_t instId,const Operand_ & o0,const FuncSignature & signature)181   inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
182     InvokeNode* node;
183     _addInvokeNode(&node, instId, o0, signature);
184     return node;
185   }
186 
187   //! \}
188 
189   //! \name Virtual Registers
190   //! \{
191 
192   //! Creates a new virtual register representing the given `typeId` and `signature`.
193   //!
194   //! \note This function is public, but it's not generally recommended to be used
195   //! by AsmJit users, use architecture-specific `newReg()` functionality instead
196   //! or functions like \ref _newReg() and \ref _newRegFmt().
197   ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name);
198 
199   //! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
200   ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr);
201 
202   //! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
203   //!
204   //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
205   ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...);
206 
207   //! Creates a new virtual register compatible with the provided reference register `ref`.
208   ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr);
209 
210   //! Creates a new virtual register compatible with the provided reference register `ref`.
211   //!
212   //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
213   ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...);
214 
215   //! Tests whether the given `id` is a valid virtual register id.
isVirtIdValid(uint32_t id)216   inline bool isVirtIdValid(uint32_t id) const noexcept {
217     uint32_t index = Operand::virtIdToIndex(id);
218     return index < _vRegArray.size();
219   }
220   //! Tests whether the given `reg` is a virtual register having a valid id.
isVirtRegValid(const BaseReg & reg)221   inline bool isVirtRegValid(const BaseReg& reg) const noexcept {
222     return isVirtIdValid(reg.id());
223   }
224 
225   //! Returns \ref VirtReg associated with the given `id`.
virtRegById(uint32_t id)226   inline VirtReg* virtRegById(uint32_t id) const noexcept {
227     ASMJIT_ASSERT(isVirtIdValid(id));
228     return _vRegArray[Operand::virtIdToIndex(id)];
229   }
230 
231   //! Returns \ref VirtReg associated with the given `reg`.
virtRegByReg(const BaseReg & reg)232   inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); }
233 
234   //! Returns \ref VirtReg associated with the given virtual register `index`.
235   //!
236   //! \note This is not the same as virtual register id. The conversion between
237   //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref
238   //! Operand_::indexToVirtId() functions.
virtRegByIndex(uint32_t index)239   inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
240 
241   //! Returns an array of all virtual registers managed by the Compiler.
virtRegs()242   inline const ZoneVector<VirtReg*>& virtRegs() const noexcept { return _vRegArray; }
243 
244   //! \name Stack
245   //! \{
246 
247   //! Creates a new stack of the given `size` and `alignment` and stores it to `out`.
248   //!
249   //! \note `name` can be used to give the stack a name, for debugging purposes.
250   ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr);
251 
252   //! Updates the stack size of a stack created by `_newStack()` by its `virtId`.
253   ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0);
254 
255   //! Updates the stack size of a stack created by `_newStack()`.
256   inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) {
257     return setStackSize(mem.id(), newSize, newAlignment);
258   }
259 
260   //! \}
261 
262   //! \name Constants
263   //! \{
264 
265   //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope).
266   //!
267   //! This function adds a constant of the given `size` to the built-in \ref
268   //! ConstPool and stores the reference to that constant to the `out` operand.
269   ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size);
270 
271   //! \}
272 
273   //! \name Miscellaneous
274   //! \{
275 
276   //! Rename the given virtual register `reg` to a formatted string `fmt`.
277   ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...);
278 
279   //! \}
280 
281   //! \name Jump Annotations
282   //! \{
283 
jumpAnnotations()284   inline const ZoneVector<JumpAnnotation*>& jumpAnnotations() const noexcept {
285     return _jumpAnnotations;
286   }
287 
288   ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation);
289   ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation);
290 
291   //! Returns a new `JumpAnnotation` instance, which can be used to aggregate
292   //! possible targets of a jump where the target is not a label, for example
293   //! to implement jump tables.
294   ASMJIT_API JumpAnnotation* newJumpAnnotation();
295 
296   //! \}
297 
298 #ifndef ASMJIT_NO_DEPRECATED
299   ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future")
alloc(BaseReg &)300   inline void alloc(BaseReg&) {}
301   ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future")
spill(BaseReg &)302   inline void spill(BaseReg&) {}
303 #endif // !ASMJIT_NO_DEPRECATED
304 
305   //! \name Events
306   //! \{
307 
308   ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
309   ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
310 
311   //! \}
312 };
313 
314 // ============================================================================
315 // [asmjit::JumpAnnotation]
316 // ============================================================================
317 
318 //! Jump annotation used to annotate jumps.
319 //!
320 //! \ref BaseCompiler allows to emit jumps where the target is either register
321 //! or memory operand. Such jumps cannot be trivially inspected, so instead of
322 //! doing heuristics AsmJit allows to annotate such jumps with possible targets.
323 //! Register allocator then use the annotation to construct control-flow, which
324 //! is then used by liveness analysis and other tools to prepare ground for
325 //! register allocation.
326 class JumpAnnotation {
327 public:
328   ASMJIT_NONCOPYABLE(JumpAnnotation)
329 
330   //! Compiler that owns this JumpAnnotation.
331   BaseCompiler* _compiler;
332   //! Annotation identifier.
333   uint32_t _annotationId;
334   //! Vector of label identifiers, see \ref labelIds().
335   ZoneVector<uint32_t> _labelIds;
336 
JumpAnnotation(BaseCompiler * compiler,uint32_t annotationId)337   inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept
338     : _compiler(compiler),
339       _annotationId(annotationId) {}
340 
341   //! Returns the compiler that owns this JumpAnnotation.
compiler()342   inline BaseCompiler* compiler() const noexcept { return _compiler; }
343   //! Returns the annotation id.
annotationId()344   inline uint32_t annotationId() const noexcept { return _annotationId; }
345   //! Returns a vector of label identifiers that lists all targets of the jump.
labelIds()346   const ZoneVector<uint32_t>& labelIds() const noexcept { return _labelIds; }
347 
348   //! Tests whether the given `label` is a target of this JumpAnnotation.
hasLabel(const Label & label)349   inline bool hasLabel(const Label& label) const noexcept { return hasLabelId(label.id()); }
350   //! Tests whether the given `labelId` is a target of this JumpAnnotation.
hasLabelId(uint32_t labelId)351   inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); }
352 
353   //! Adds the `label` to the list of targets of this JumpAnnotation.
addLabel(const Label & label)354   inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); }
355   //! Adds the `labelId` to the list of targets of this JumpAnnotation.
addLabelId(uint32_t labelId)356   inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); }
357 };
358 
359 // ============================================================================
360 // [asmjit::JumpNode]
361 // ============================================================================
362 
363 //! Jump instruction with \ref JumpAnnotation.
364 //!
365 //! \note This node should be only used to represent jump where the jump target
366 //! cannot be deduced by examining instruction operands. For example if the jump
367 //! target is register or memory location. This pattern is often used to perform
368 //! indirect jumps that use jump table, e.g. to implement `switch{}` statement.
369 class JumpNode : public InstNode {
370 public:
ASMJIT_NONCOPYABLE(JumpNode)371   ASMJIT_NONCOPYABLE(JumpNode)
372 
373   JumpAnnotation* _annotation;
374 
375   //! \name Construction & Destruction
376   //! \{
377 
378   ASMJIT_INLINE JumpNode(BaseCompiler* cc, uint32_t instId, uint32_t options, uint32_t opCount, JumpAnnotation* annotation) noexcept
379     : InstNode(cc, instId, options, opCount, kBaseOpCapacity),
380       _annotation(annotation) {
381     setType(kNodeJump);
382   }
383 
384   //! \}
385 
386   //! \name Accessors
387   //! \{
388 
389   //! Tests whether this JumpNode has associated a \ref JumpAnnotation.
hasAnnotation()390   inline bool hasAnnotation() const noexcept { return _annotation != nullptr; }
391   //! Returns the \ref JumpAnnotation associated with this jump, or `nullptr`.
annotation()392   inline JumpAnnotation* annotation() const noexcept { return _annotation; }
393   //! Sets the \ref JumpAnnotation associated with this jump to `annotation`.
setAnnotation(JumpAnnotation * annotation)394   inline void setAnnotation(JumpAnnotation* annotation) noexcept { _annotation = annotation; }
395 
396   //! \}
397 };
398 
399 // ============================================================================
400 // [asmjit::FuncNode]
401 // ============================================================================
402 
403 //! Function node represents a function used by \ref BaseCompiler.
404 //!
405 //! A function is composed of the following:
406 //!
407 //!   - Function entry, \ref FuncNode acts as a label, so the entry is implicit.
408 //!     To get the entry, simply use \ref FuncNode::label(), which is the same
409 //!     as \ref LabelNode::label().
410 //!
411 //!   - Function exit, which is represented by \ref FuncNode::exitNode(). A
412 //!     helper function \ref FuncNode::exitLabel() exists and returns an exit
413 //!     label instead of node.
414 //!
415 //!   - Function \ref FuncNode::endNode() sentinel. This node marks the end of
416 //!     a function - there should be no code that belongs to the function after
417 //!     this node, but the Compiler doesn't enforce that at the moment.
418 //!
419 //!   - Function detail, see \ref FuncNode::detail().
420 //!
421 //!   - Function frame, see \ref FuncNode::frame().
422 //!
423 //!   - Function arguments mapped to virtual registers, see \ref FuncNode::args().
424 //!
425 //! In a node list, the function and its body looks like the following:
426 //!
427 //! \code{.unparsed}
428 //! [...]       - Anything before the function.
429 //!
430 //! [FuncNode]  - Entry point of the function, acts as a label as well.
431 //!   <Prolog>  - Prolog inserted by the register allocator.
432 //!   {...}     - Function body - user code basically.
433 //! [ExitLabel] - Exit label
434 //!   <Epilog>  - Epilog inserted by the register allocator.
435 //!   <Return>  - Return inserted by the register allocator.
436 //!   {...}     - Can contain data or user code (error handling, special cases, ...).
437 //! [FuncEnd]   - End sentinel
438 //!
439 //! [...]       - Anything after the function.
440 //! \endcode
441 //!
442 //! When a function is added to the compiler by \ref BaseCompiler::addFunc() it
443 //! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the
444 //! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called
445 //! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel
446 //! as a marker after additional code or data can be placed, and it's a common
447 //! practice.
448 class FuncNode : public LabelNode {
449 public:
450   ASMJIT_NONCOPYABLE(FuncNode)
451 
452   //! Arguments pack.
453   struct ArgPack {
454     VirtReg* _data[Globals::kMaxValuePack];
455 
resetArgPack456     inline void reset() noexcept {
457       for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
458         _data[valueIndex] = nullptr;
459     }
460 
461     inline VirtReg*& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; }
462     inline VirtReg* const& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
463   };
464 
465   //! Function detail.
466   FuncDetail _funcDetail;
467   //! Function frame.
468   FuncFrame _frame;
469   //! Function exit label.
470   LabelNode* _exitNode;
471   //! Function end (sentinel).
472   SentinelNode* _end;
473 
474   //! Argument packs.
475   ArgPack* _args;
476 
477   //! \name Construction & Destruction
478   //! \{
479 
480   //! Creates a new `FuncNode` instance.
481   //!
482   //! Always use `BaseCompiler::addFunc()` to create `FuncNode`.
FuncNode(BaseBuilder * cb)483   ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept
484     : LabelNode(cb),
485       _funcDetail(),
486       _frame(),
487       _exitNode(nullptr),
488       _end(nullptr),
489       _args(nullptr) {
490     setType(kNodeFunc);
491   }
492 
493   //! \}
494 
495   //! \{
496   //! \name Accessors
497 
498   //! Returns function exit `LabelNode`.
exitNode()499   inline LabelNode* exitNode() const noexcept { return _exitNode; }
500   //! Returns function exit label.
exitLabel()501   inline Label exitLabel() const noexcept { return _exitNode->label(); }
502 
503   //! Returns "End of Func" sentinel.
endNode()504   inline SentinelNode* endNode() const noexcept { return _end; }
505 
506   //! Returns function declaration.
detail()507   inline FuncDetail& detail() noexcept { return _funcDetail; }
508   //! Returns function declaration.
detail()509   inline const FuncDetail& detail() const noexcept { return _funcDetail; }
510 
511   //! Returns function frame.
frame()512   inline FuncFrame& frame() noexcept { return _frame; }
513   //! Returns function frame.
frame()514   inline const FuncFrame& frame() const noexcept { return _frame; }
515 
516   //! Tests whether the function has a return value.
hasRet()517   inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
518   //! Returns arguments count.
argCount()519   inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
520 
521   //! Returns argument packs.
argPacks()522   inline ArgPack* argPacks() const noexcept { return _args; }
523 
524   //! Returns argument pack at `argIndex`.
argPack(size_t argIndex)525   inline ArgPack& argPack(size_t argIndex) const noexcept {
526     ASMJIT_ASSERT(argIndex < argCount());
527     return _args[argIndex];
528   }
529 
530   //! Sets argument at `argIndex`.
setArg(size_t argIndex,VirtReg * vReg)531   inline void setArg(size_t argIndex, VirtReg* vReg) noexcept {
532     ASMJIT_ASSERT(argIndex < argCount());
533     _args[argIndex][0] = vReg;
534   }
535 
536   //! Sets argument at `argIndex` and `valueIndex`.
setArg(size_t argIndex,size_t valueIndex,VirtReg * vReg)537   inline void setArg(size_t argIndex, size_t valueIndex, VirtReg* vReg) noexcept {
538     ASMJIT_ASSERT(argIndex < argCount());
539     _args[argIndex][valueIndex] = vReg;
540   }
541 
542   //! Resets argument pack at `argIndex`.
resetArg(size_t argIndex)543   inline void resetArg(size_t argIndex) noexcept {
544     ASMJIT_ASSERT(argIndex < argCount());
545     _args[argIndex].reset();
546   }
547 
548   //! Resets argument pack at `argIndex`.
resetArg(size_t argIndex,size_t valueIndex)549   inline void resetArg(size_t argIndex, size_t valueIndex) noexcept {
550     ASMJIT_ASSERT(argIndex < argCount());
551     _args[argIndex][valueIndex] = nullptr;
552   }
553 
554   //! Returns function attributes.
attributes()555   inline uint32_t attributes() const noexcept { return _frame.attributes(); }
556   //! Adds `attrs` to the function attributes.
addAttributes(uint32_t attrs)557   inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); }
558 
559   //! \}
560 };
561 
562 // ============================================================================
563 // [asmjit::FuncRetNode]
564 // ============================================================================
565 
566 //! Function return, used by \ref BaseCompiler.
567 class FuncRetNode : public InstNode {
568 public:
ASMJIT_NONCOPYABLE(FuncRetNode)569   ASMJIT_NONCOPYABLE(FuncRetNode)
570 
571   //! \name Construction & Destruction
572   //! \{
573 
574   //! Creates a new `FuncRetNode` instance.
575   inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) {
576     _any._nodeType = kNodeFuncRet;
577   }
578 
579   //! \}
580 };
581 
582 // ============================================================================
583 // [asmjit::InvokeNode]
584 // ============================================================================
585 
586 //! Function invocation, used by \ref BaseCompiler.
587 class InvokeNode : public InstNode {
588 public:
589   ASMJIT_NONCOPYABLE(InvokeNode)
590 
591   //! Operand pack provides multiple operands that can be associated with a
592   //! single return value of function argument. Sometims this is necessary to
593   //! express an argument or return value that requires multiple registers, for
594   //! example 64-bit value in 32-bit mode or passing / returning homogenous data
595   //! structures.
596   struct OperandPack {
597     //! Operands.
598     Operand_ _data[Globals::kMaxValuePack];
599 
600     //! Reset the pack by resetting all operands in the pack.
resetOperandPack601     inline void reset() noexcept {
602       for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
603         _data[valueIndex].reset();
604     }
605 
606     //! Returns an operand at the given `valueIndex`.
607     inline Operand& operator[](size_t valueIndex) noexcept {
608       ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack);
609       return _data[valueIndex].as<Operand>();
610     }
611 
612     //! Returns an operand at the given `valueIndex` (const).
613     const inline Operand& operator[](size_t valueIndex) const noexcept {
614       ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack);
615       return _data[valueIndex].as<Operand>();
616     }
617   };
618 
619   //! Function detail.
620   FuncDetail _funcDetail;
621   //! Function return value(s).
622   OperandPack _rets;
623   //! Function arguments.
624   OperandPack* _args;
625 
626   //! \name Construction & Destruction
627   //! \{
628 
629   //! Creates a new `InvokeNode` instance.
InvokeNode(BaseBuilder * cb,uint32_t instId,uint32_t options)630   inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept
631     : InstNode(cb, instId, options, kBaseOpCapacity),
632       _funcDetail(),
633       _args(nullptr) {
634     setType(kNodeInvoke);
635     _resetOps();
636     _rets.reset();
637     addFlags(kFlagIsRemovable);
638   }
639 
640   //! \}
641 
642   //! \name Accessors
643   //! \{
644 
645   //! Sets the function signature.
init(const FuncSignature & signature,const Environment & environment)646   inline Error init(const FuncSignature& signature, const Environment& environment) noexcept {
647     return _funcDetail.init(signature, environment);
648   }
649 
650   //! Returns the function detail.
detail()651   inline FuncDetail& detail() noexcept { return _funcDetail; }
652   //! Returns the function detail.
detail()653   inline const FuncDetail& detail() const noexcept { return _funcDetail; }
654 
655   //! Returns the target operand.
target()656   inline Operand& target() noexcept { return _opArray[0].as<Operand>(); }
657   //! \overload
target()658   inline const Operand& target() const noexcept { return _opArray[0].as<Operand>(); }
659 
660   //! Returns the number of function return values.
hasRet()661   inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
662   //! Returns the number of function arguments.
argCount()663   inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
664 
665   //! Returns operand pack representing function return value(s).
retPack()666   inline OperandPack& retPack() noexcept { return _rets; }
667   //! Returns operand pack representing function return value(s).
retPack()668   inline const OperandPack& retPack() const noexcept { return _rets; }
669 
670   //! Returns the return value at the given `valueIndex`.
671   inline Operand& ret(size_t valueIndex = 0) noexcept { return _rets[valueIndex]; }
672   //! \overload
673   inline const Operand& ret(size_t valueIndex = 0) const noexcept { return _rets[valueIndex]; }
674 
675   //! Returns operand pack representing function return value(s).
argPack(size_t argIndex)676   inline OperandPack& argPack(size_t argIndex) noexcept {
677     ASMJIT_ASSERT(argIndex < argCount());
678     return _args[argIndex];
679   }
680   //! \overload
argPack(size_t argIndex)681   inline const OperandPack& argPack(size_t argIndex) const noexcept {
682     ASMJIT_ASSERT(argIndex < argCount());
683     return _args[argIndex];
684   }
685 
686   //! Returns a function argument at the given `argIndex`.
arg(size_t argIndex,size_t valueIndex)687   inline Operand& arg(size_t argIndex, size_t valueIndex) noexcept {
688     ASMJIT_ASSERT(argIndex < argCount());
689     return _args[argIndex][valueIndex];
690   }
691   //! \overload
arg(size_t argIndex,size_t valueIndex)692   inline const Operand& arg(size_t argIndex, size_t valueIndex) const noexcept {
693     ASMJIT_ASSERT(argIndex < argCount());
694     return _args[argIndex][valueIndex];
695   }
696 
697   //! Sets the function return value at `i` to `op`.
_setRet(size_t valueIndex,const Operand_ & op)698   inline void _setRet(size_t valueIndex, const Operand_& op) noexcept { _rets[valueIndex] = op; }
699   //! Sets the function argument at `i` to `op`.
_setArg(size_t argIndex,size_t valueIndex,const Operand_ & op)700   inline void _setArg(size_t argIndex, size_t valueIndex, const Operand_& op) noexcept {
701     ASMJIT_ASSERT(argIndex < argCount());
702     _args[argIndex][valueIndex] = op;
703   }
704 
705   //! Sets the function return value at `valueIndex` to `reg`.
setRet(size_t valueIndex,const BaseReg & reg)706   inline void setRet(size_t valueIndex, const BaseReg& reg) noexcept { _setRet(valueIndex, reg); }
707 
708   //! Sets the first function argument in a value-pack at `argIndex` to `reg`.
setArg(size_t argIndex,const BaseReg & reg)709   inline void setArg(size_t argIndex, const BaseReg& reg) noexcept { _setArg(argIndex, 0, reg); }
710   //! Sets the first function argument in a value-pack at `argIndex` to `imm`.
setArg(size_t argIndex,const Imm & imm)711   inline void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); }
712 
713   //! Sets the function argument at `argIndex` and `valueIndex` to `reg`.
setArg(size_t argIndex,size_t valueIndex,const BaseReg & reg)714   inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) noexcept { _setArg(argIndex, valueIndex, reg); }
715   //! Sets the function argument at `argIndex` and `valueIndex` to `imm`.
setArg(size_t argIndex,size_t valueIndex,const Imm & imm)716   inline void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); }
717 
718   //! \}
719 };
720 
721 // ============================================================================
722 // [asmjit::FuncPass]
723 // ============================================================================
724 
725 //! Function pass extends \ref Pass with \ref FuncPass::runOnFunction().
726 class ASMJIT_VIRTAPI FuncPass : public Pass {
727 public:
728   ASMJIT_NONCOPYABLE(FuncPass)
729   typedef Pass Base;
730 
731   //! \name Construction & Destruction
732   //! \{
733 
734   ASMJIT_API FuncPass(const char* name) noexcept;
735 
736   //! \}
737 
738   //! \name Accessors
739   //! \{
740 
741   //! Returns the associated `BaseCompiler`.
cc()742   inline BaseCompiler* cc() const noexcept { return static_cast<BaseCompiler*>(_cb); }
743 
744   //! \}
745 
746   //! \name Run
747   //! \{
748 
749   //! Calls `runOnFunction()` on each `FuncNode` node found.
750   ASMJIT_API Error run(Zone* zone, Logger* logger) override;
751 
752   //! Called once per `FuncNode`.
753   virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0;
754 
755   //! \}
756 };
757 
758 //! \}
759 
760 ASMJIT_END_NAMESPACE
761 
762 #endif // !ASMJIT_NO_COMPILER
763 #endif // ASMJIT_CORE_COMPILER_H_INCLUDED
764