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

Generated by: LCOV version 1.16