summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/src/asmjit/core/compiler.h
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/src/asmjit/core/compiler.h')
-rw-r--r--3rdparty/asmjit/src/asmjit/core/compiler.h639
1 files changed, 280 insertions, 359 deletions
diff --git a/3rdparty/asmjit/src/asmjit/core/compiler.h b/3rdparty/asmjit/src/asmjit/core/compiler.h
index 71f89ec701e..709fd952acc 100644
--- a/3rdparty/asmjit/src/asmjit/core/compiler.h
+++ b/3rdparty/asmjit/src/asmjit/core/compiler.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project <https://asmjit.com>
//
-// * Official AsmJit Home Page: https://asmjit.com
-// * Official Github Repository: https://github.com/asmjit/asmjit
-//
-// Copyright (c) 2008-2020 The AsmJit Authors
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-// 3. This notice may not be removed or altered from any source distribution.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
#define ASMJIT_CORE_COMPILER_H_INCLUDED
@@ -30,6 +12,7 @@
#include "../core/assembler.h"
#include "../core/builder.h"
#include "../core/constpool.h"
+#include "../core/compilerdefs.h"
#include "../core/func.h"
#include "../core/inst.h"
#include "../core/operand.h"
@@ -39,15 +22,7 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
-struct RATiedReg;
-class RAWorkReg;
-
class JumpAnnotation;
-
class JumpNode;
class FuncNode;
class FuncRetNode;
@@ -56,150 +31,18 @@ class InvokeNode;
//! \addtogroup asmjit_compiler
//! \{
-// ============================================================================
-// [asmjit::VirtReg]
-// ============================================================================
-
-//! Virtual register data, managed by \ref BaseCompiler.
-class VirtReg {
-public:
- ASMJIT_NONCOPYABLE(VirtReg)
-
- //! Virtual register id.
- uint32_t _id;
- //! Virtual register info (signature).
- RegInfo _info;
- //! Virtual register size (can be smaller than `regInfo._size`).
- uint32_t _virtSize;
- //! Virtual register alignment (for spilling).
- uint8_t _alignment;
- //! Type-id.
- uint8_t _typeId;
- //! Virtual register weight for alloc/spill decisions.
- uint8_t _weight;
- //! True if this is a fixed register, never reallocated.
- uint8_t _isFixed : 1;
- //! True if the virtual register is only used as a stack (never accessed as register).
- uint8_t _isStack : 1;
- uint8_t _reserved : 6;
-
- //! Virtual register name (user provided or automatically generated).
- ZoneString<16> _name;
-
- // -------------------------------------------------------------------------
- // The following members are used exclusively by RAPass. They are initialized
- // when the VirtReg is created to NULL pointers and then changed during RAPass
- // execution. RAPass sets them back to NULL before it returns.
- // -------------------------------------------------------------------------
-
- //! Reference to `RAWorkReg`, used during register allocation.
- RAWorkReg* _workReg;
-
- //! \name Construction & Destruction
- //! \{
-
- inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept
- : _id(id),
- _virtSize(virtSize),
- _alignment(uint8_t(alignment)),
- _typeId(uint8_t(typeId)),
- _weight(1),
- _isFixed(false),
- _isStack(false),
- _reserved(0),
- _name(),
- _workReg(nullptr) { _info._signature = signature; }
-
- //! \}
-
- //! \name Accessors
- //! \{
-
- //! Returns the virtual register id.
- inline uint32_t id() const noexcept { return _id; }
-
- //! Returns the virtual register name.
- inline const char* name() const noexcept { return _name.data(); }
- //! Returns the size of the virtual register name.
- inline uint32_t nameSize() const noexcept { return _name.size(); }
-
- //! Returns a register information that wraps the register signature.
- inline const RegInfo& info() const noexcept { return _info; }
- //! Returns a virtual register type (maps to the physical register type as well).
- inline uint32_t type() const noexcept { return _info.type(); }
- //! Returns a virtual register group (maps to the physical register group as well).
- inline uint32_t group() const noexcept { return _info.group(); }
-
- //! Returns a real size of the register this virtual register maps to.
- //!
- //! For example if this is a 128-bit SIMD register used for a scalar single
- //! precision floating point value then its virtSize would be 4, however, the
- //! `regSize` would still say 16 (128-bits), because it's the smallest size
- //! of that register type.
- inline uint32_t regSize() const noexcept { return _info.size(); }
-
- //! Returns a register signature of this virtual register.
- inline uint32_t signature() const noexcept { return _info.signature(); }
-
- //! Returns the virtual register size.
- //!
- //! The virtual register size describes how many bytes the virtual register
- //! needs to store its content. It can be smaller than the physical register
- //! size, see `regSize()`.
- inline uint32_t virtSize() const noexcept { return _virtSize; }
-
- //! Returns the virtual register alignment.
- inline uint32_t alignment() const noexcept { return _alignment; }
-
- //! Returns the virtual register type id, see `Type::Id`.
- inline uint32_t typeId() const noexcept { return _typeId; }
-
- //! Returns the virtual register weight - the register allocator can use it
- //! as explicit hint for alloc/spill decisions.
- inline uint32_t weight() const noexcept { return _weight; }
- //! Sets the virtual register weight (0 to 255) - the register allocator can
- //! use it as explicit hint for alloc/spill decisions and initial bin-packing.
- inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); }
-
- //! Returns whether the virtual register is always allocated to a fixed
- //! physical register (and never reallocated).
- //!
- //! \note This is only used for special purposes and it's mostly internal.
- inline bool isFixed() const noexcept { return bool(_isFixed); }
-
- //! Returns whether the virtual register is indeed a stack that only uses
- //! the virtual register id for making it accessible.
- //!
- //! \note It's an error if a stack is accessed as a register.
- inline bool isStack() const noexcept { return bool(_isStack); }
-
- inline bool hasWorkReg() const noexcept { return _workReg != nullptr; }
- inline RAWorkReg* workReg() const noexcept { return _workReg; }
- inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; }
- inline void resetWorkReg() noexcept { _workReg = nullptr; }
-
- //! \}
-};
-
-// ============================================================================
-// [asmjit::BaseCompiler]
-// ============================================================================
-
//! Code emitter that uses virtual registers and performs register allocation.
//!
-//! Compiler is a high-level code-generation tool that provides register
-//! allocation and automatic handling of function calling conventions. It was
-//! primarily designed for merging multiple parts of code into a function
-//! without worrying about registers and function calling conventions.
+//! Compiler is a high-level code-generation tool that provides register allocation and automatic handling of function
+//! calling conventions. It was primarily designed for merging multiple parts of code into a function without worrying
+//! about registers and function calling conventions.
//!
-//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and
-//! 64-bit code generation within a single code base.
+//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit code generation within a single code
+//! base.
//!
-//! BaseCompiler is based on BaseBuilder and contains all the features it
-//! provides. It means that the code it stores can be modified (removed, added,
-//! injected) and analyzed. When the code is finalized the compiler can emit
-//! the code into an Assembler to translate the abstract representation into a
-//! machine code.
+//! BaseCompiler is based on BaseBuilder and contains all the features it provides. It means that the code it stores
+//! can be modified (removed, added, injected) and analyzed. When the code is finalized the compiler can emit the code
+//! into an Assembler to translate the abstract representation into a machine code.
//!
//! Check out architecture specific compilers for more details and examples:
//!
@@ -209,6 +52,9 @@ public:
ASMJIT_NONCOPYABLE(BaseCompiler)
typedef BaseBuilder Base;
+ //! \name Members
+ //! \{
+
//! Current function.
FuncNode* _func;
//! Allocates `VirtReg` objects.
@@ -218,10 +64,12 @@ public:
//! Stores jump annotations.
ZoneVector<JumpAnnotation*> _jumpAnnotations;
- //! Local constant pool, flushed at the end of each function.
- ConstPoolNode* _localConstPool;
- //! Global constant pool, flushed by `finalize()`.
- ConstPoolNode* _globalConstPool;
+ //! Local and global constant pools.
+ //!
+ //! Local constant pool is flushed with each function, global constant pool is flushed only by \ref finalize().
+ ConstPoolNode* _constPools[2];
+
+ //! \}
//! \name Construction & Destruction
//! \{
@@ -236,52 +84,54 @@ public:
//! \name Function Management
//! \{
- //! Returns the current function.
- inline FuncNode* func() const noexcept { return _func; }
-
//! Creates a new \ref FuncNode.
- ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature);
- //! Creates a new \ref FuncNode adds it to the compiler.
- ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature);
+ ASMJIT_API Error newFuncNode(FuncNode** ASMJIT_NONNULL(out), const FuncSignature& signature);
+ //! Creates a new \ref FuncNode adds it to the instruction stream.
+ ASMJIT_API Error addFuncNode(FuncNode** ASMJIT_NONNULL(out), const FuncSignature& signature);
//! Creates a new \ref FuncRetNode.
- ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
- //! Creates a new \ref FuncRetNode and adds it to the compiler.
- ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
+ ASMJIT_API Error newFuncRetNode(FuncRetNode** ASMJIT_NONNULL(out), const Operand_& o0, const Operand_& o1);
+ //! Creates a new \ref FuncRetNode and adds it to the instruction stream.
+ ASMJIT_API Error addFuncRetNode(FuncRetNode** ASMJIT_NONNULL(out), const Operand_& o0, const Operand_& o1);
+
+ //! Returns the current function.
+ inline FuncNode* func() const noexcept { return _func; }
//! Creates a new \ref FuncNode with the given `signature` and returns it.
inline FuncNode* newFunc(const FuncSignature& signature) {
FuncNode* node;
- _newFuncNode(&node, signature);
+ newFuncNode(&node, signature);
return node;
}
- //! Creates a new \ref FuncNode with the given `signature`, adds it to the
- //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it.
+ //! Creates a new \ref FuncNode with the given `signature`, adds it to the instruction stream by using
+ //! the \ref addFunc(FuncNode*) overload, and returns it.
inline FuncNode* addFunc(const FuncSignature& signature) {
FuncNode* node;
- _addFuncNode(&node, signature);
+ addFuncNode(&node, signature);
return node;
}
//! Adds a function `node` to the instruction stream.
- ASMJIT_API FuncNode* addFunc(FuncNode* func);
+ ASMJIT_API FuncNode* addFunc(FuncNode* ASMJIT_NONNULL(func));
//! Emits a sentinel that marks the end of the current function.
ASMJIT_API Error endFunc();
+#if !defined(ASMJIT_NO_DEPRECATED)
+ inline Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg);
+
//! Sets a function argument at `argIndex` to `reg`.
- ASMJIT_API Error setArg(uint32_t argIndex, const BaseReg& reg);
+ ASMJIT_DEPRECATED("Setting arguments through Compiler is deprecated, use FuncNode->setArg() instead")
+ inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); }
- inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) {
- FuncRetNode* node;
- _newRetNode(&node, o0, o1);
- return node;
- }
+ //! Sets a function argument at `argIndex` at `valueIndex` to `reg`.
+ ASMJIT_DEPRECATED("Setting arguments through Compiler is deprecated, use FuncNode->setArg() instead")
+ inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); }
+#endif
- inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) {
+ inline Error addRet(const Operand_& o0, const Operand_& o1) {
FuncRetNode* node;
- _addRetNode(&node, o0, o1);
- return node;
+ return addFuncRetNode(&node, o0, o1);
}
//! \}
@@ -290,23 +140,9 @@ public:
//! \{
//! Creates a new \ref InvokeNode.
- ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
- //! Creates a new \ref InvokeNode and adds it to Compiler.
- ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
-
- //! Creates a new `InvokeNode`.
- inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
- InvokeNode* node;
- _newInvokeNode(&node, instId, o0, signature);
- return node;
- }
-
- //! Adds a new `InvokeNode`.
- inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
- InvokeNode* node;
- _addInvokeNode(&node, instId, o0, signature);
- return node;
- }
+ ASMJIT_API Error newInvokeNode(InvokeNode** ASMJIT_NONNULL(out), InstId instId, const Operand_& o0, const FuncSignature& signature);
+ //! Creates a new \ref InvokeNode and adds it to the instruction stream.
+ ASMJIT_API Error addInvokeNode(InvokeNode** ASMJIT_NONNULL(out), InstId instId, const Operand_& o0, const FuncSignature& signature);
//! \}
@@ -315,26 +151,25 @@ public:
//! Creates a new virtual register representing the given `typeId` and `signature`.
//!
- //! \note This function is public, but it's not generally recommended to be used
- //! by AsmJit users, use architecture-specific `newReg()` functionality instead
- //! or functions like \ref _newReg() and \ref _newRegFmt().
- ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name);
+ //! \note This function is public, but it's not generally recommended to be used by AsmJit users, use architecture
+ //! specific `newReg()` functionality instead or functions like \ref _newReg() and \ref _newRegFmt().
+ ASMJIT_API Error newVirtReg(VirtReg** ASMJIT_NONNULL(out), TypeId typeId, OperandSignature signature, const char* name);
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
- ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr);
+ ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* name = nullptr);
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
//!
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
- ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...);
+ ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* fmt, ...);
//! Creates a new virtual register compatible with the provided reference register `ref`.
- ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr);
+ ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* name = nullptr);
//! Creates a new virtual register compatible with the provided reference register `ref`.
//!
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
- ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...);
+ ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* fmt, ...);
//! Tests whether the given `id` is a valid virtual register id.
inline bool isVirtIdValid(uint32_t id) const noexcept {
@@ -357,9 +192,8 @@ public:
//! Returns \ref VirtReg associated with the given virtual register `index`.
//!
- //! \note This is not the same as virtual register id. The conversion between
- //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref
- //! Operand_::indexToVirtId() functions.
+ //! \note This is not the same as virtual register id. The conversion between id and its index is implemented
+ //! by \ref Operand_::virtIdToIndex() and \ref Operand_::indexToVirtId() functions.
inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
//! Returns an array of all virtual registers managed by the Compiler.
@@ -371,7 +205,7 @@ public:
//! Creates a new stack of the given `size` and `alignment` and stores it to `out`.
//!
//! \note `name` can be used to give the stack a name, for debugging purposes.
- ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr);
+ ASMJIT_API Error _newStack(BaseMem* ASMJIT_NONNULL(out), uint32_t size, uint32_t alignment, const char* name = nullptr);
//! Updates the stack size of a stack created by `_newStack()` by its `virtId`.
ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0);
@@ -386,11 +220,11 @@ public:
//! \name Constants
//! \{
- //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope).
+ //! Creates a new constant of the given `scope` (see \ref ConstPoolScope).
//!
- //! This function adds a constant of the given `size` to the built-in \ref
- //! ConstPool and stores the reference to that constant to the `out` operand.
- ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size);
+ //! This function adds a constant of the given `size` to the built-in \ref ConstPool and stores the reference to that
+ //! constant to the `out` operand.
+ ASMJIT_API Error _newConst(BaseMem* ASMJIT_NONNULL(out), ConstPoolScope scope, const void* data, size_t size);
//! \}
@@ -409,23 +243,15 @@ public:
return _jumpAnnotations;
}
- ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation);
- ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation);
+ ASMJIT_API Error newJumpNode(JumpNode** ASMJIT_NONNULL(out), InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation);
+ ASMJIT_API Error emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation);
- //! Returns a new `JumpAnnotation` instance, which can be used to aggregate
- //! possible targets of a jump where the target is not a label, for example
- //! to implement jump tables.
+ //! Returns a new `JumpAnnotation` instance, which can be used to aggregate possible targets of a jump where the
+ //! target is not a label, for example to implement jump tables.
ASMJIT_API JumpAnnotation* newJumpAnnotation();
//! \}
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future")
- inline void alloc(BaseReg&) {}
- ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future")
- inline void spill(BaseReg&) {}
-#endif // !ASMJIT_NO_DEPRECATED
-
//! \name Events
//! \{
@@ -435,22 +261,19 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::JumpAnnotation]
-// ============================================================================
-
//! Jump annotation used to annotate jumps.
//!
-//! \ref BaseCompiler allows to emit jumps where the target is either register
-//! or memory operand. Such jumps cannot be trivially inspected, so instead of
-//! doing heuristics AsmJit allows to annotate such jumps with possible targets.
-//! Register allocator then use the annotation to construct control-flow, which
-//! is then used by liveness analysis and other tools to prepare ground for
-//! register allocation.
+//! \ref BaseCompiler allows to emit jumps where the target is either register or memory operand. Such jumps cannot be
+//! trivially inspected, so instead of doing heuristics AsmJit allows to annotate such jumps with possible targets.
+//! Register allocator then uses the annotation to construct control-flow, which is then used by liveness analysis and
+//! other tools to prepare ground for register allocation.
class JumpAnnotation {
public:
ASMJIT_NONCOPYABLE(JumpAnnotation)
+ //! \name Members
+ //! \{
+
//! Compiler that owns this JumpAnnotation.
BaseCompiler* _compiler;
//! Annotation identifier.
@@ -458,10 +281,20 @@ public:
//! Vector of label identifiers, see \ref labelIds().
ZoneVector<uint32_t> _labelIds;
- inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept
+ //! \}
+
+ //! \name Construction & Destruction
+ //! \{
+
+ inline JumpAnnotation(BaseCompiler* ASMJIT_NONNULL(compiler), uint32_t annotationId) noexcept
: _compiler(compiler),
_annotationId(annotationId) {}
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
//! Returns the compiler that owns this JumpAnnotation.
inline BaseCompiler* compiler() const noexcept { return _compiler; }
//! Returns the annotation id.
@@ -474,35 +307,42 @@ public:
//! Tests whether the given `labelId` is a target of this JumpAnnotation.
inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); }
+ //! \}
+
+ //! \name Annotation Building API
+ //! \{
+
//! Adds the `label` to the list of targets of this JumpAnnotation.
inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); }
//! Adds the `labelId` to the list of targets of this JumpAnnotation.
inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); }
-};
-// ============================================================================
-// [asmjit::JumpNode]
-// ============================================================================
+ //! \}
+};
//! Jump instruction with \ref JumpAnnotation.
//!
-//! \note This node should be only used to represent jump where the jump target
-//! cannot be deduced by examining instruction operands. For example if the jump
-//! target is register or memory location. This pattern is often used to perform
-//! indirect jumps that use jump table, e.g. to implement `switch{}` statement.
+//! \note This node should be only used to represent jump where the jump target cannot be deduced by examining
+//! instruction operands. For example if the jump target is register or memory location. This pattern is often
+//! used to perform indirect jumps that use jump table, e.g. to implement `switch{}` statement.
class JumpNode : public InstNode {
public:
ASMJIT_NONCOPYABLE(JumpNode)
+ //! \name Members
+ //! \{
+
JumpAnnotation* _annotation;
+ //! \}
+
//! \name Construction & Destruction
//! \{
- ASMJIT_INLINE JumpNode(BaseCompiler* cc, uint32_t instId, uint32_t options, uint32_t opCount, JumpAnnotation* annotation) noexcept
+ inline JumpNode(BaseCompiler* ASMJIT_NONNULL(cc), InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept
: InstNode(cc, instId, options, opCount, kBaseOpCapacity),
_annotation(annotation) {
- setType(kNodeJump);
+ setType(NodeType::kJump);
}
//! \}
@@ -520,31 +360,24 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::FuncNode]
-// ============================================================================
-
//! Function node represents a function used by \ref BaseCompiler.
//!
//! A function is composed of the following:
//!
-//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit.
-//! To get the entry, simply use \ref FuncNode::label(), which is the same
-//! as \ref LabelNode::label().
+//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. To get the entry, simply use
+//! \ref FuncNode::label(), which is the same as \ref LabelNode::label().
//!
-//! - Function exit, which is represented by \ref FuncNode::exitNode(). A
-//! helper function \ref FuncNode::exitLabel() exists and returns an exit
-//! label instead of node.
+//! - Function exit, which is represented by \ref FuncNode::exitNode(). A helper function
+//! \ref FuncNode::exitLabel() exists and returns an exit label instead of node.
//!
-//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of
-//! a function - there should be no code that belongs to the function after
-//! this node, but the Compiler doesn't enforce that at the moment.
+//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of a function - there should be no
+//! code that belongs to the function after this node, but the Compiler doesn't enforce that at the moment.
//!
//! - Function detail, see \ref FuncNode::detail().
//!
//! - Function frame, see \ref FuncNode::frame().
//!
-//! - Function arguments mapped to virtual registers, see \ref FuncNode::args().
+//! - Function arguments mapped to virtual registers, see \ref FuncNode::argPacks().
//!
//! In a node list, the function and its body looks like the following:
//!
@@ -563,16 +396,30 @@ public:
//! [...] - Anything after the function.
//! \endcode
//!
-//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it
-//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the
-//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called
-//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel
-//! as a marker after additional code or data can be placed, and it's a common
-//! practice.
+//! When a function is added to the instruction stream by \ref BaseCompiler::addFunc() it actually inserts 3 nodes
+//! (FuncNode, ExitLabel, and FuncEnd) and sets the current cursor to be FuncNode. When \ref BaseCompiler::endFunc()
+//! is called the cursor is set to FuncEnd. This guarantees that user can use ExitLabel as a marker after additional
+//! code or data can be placed, which is a common practice.
class FuncNode : public LabelNode {
public:
ASMJIT_NONCOPYABLE(FuncNode)
+ //! Arguments pack.
+ struct ArgPack {
+ RegOnly _data[Globals::kMaxValuePack];
+
+ inline void reset() noexcept {
+ for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
+ _data[valueIndex].reset();
+ }
+
+ inline RegOnly& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; }
+ inline const RegOnly& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
+ };
+
+ //! \name Members
+ //! \{
+
//! Function detail.
FuncDetail _funcDetail;
//! Function frame.
@@ -581,23 +428,25 @@ public:
LabelNode* _exitNode;
//! Function end (sentinel).
SentinelNode* _end;
- //! Arguments array as `VirtReg`.
- VirtReg** _args;
+ //! Argument packs.
+ ArgPack* _args;
+
+ //! \}
//! \name Construction & Destruction
//! \{
//! Creates a new `FuncNode` instance.
//!
- //! Always use `BaseCompiler::addFunc()` to create `FuncNode`.
- ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept
+ //! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`.
+ inline FuncNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept
: LabelNode(cb),
_funcDetail(),
_frame(),
_exitNode(nullptr),
_end(nullptr),
_args(nullptr) {
- setType(kNodeFunc);
+ setType(NodeType::kFunc);
}
//! \}
@@ -610,12 +459,12 @@ public:
//! Returns function exit label.
inline Label exitLabel() const noexcept { return _exitNode->label(); }
- //! Returns "End of Func" sentinel.
+ //! Returns "End of Func" sentinel node.
inline SentinelNode* endNode() const noexcept { return _end; }
- //! Returns function declaration.
+ //! Returns function detail.
inline FuncDetail& detail() noexcept { return _funcDetail; }
- //! Returns function declaration.
+ //! Returns function detail.
inline const FuncDetail& detail() const noexcept { return _funcDetail; }
//! Returns function frame.
@@ -623,44 +472,64 @@ public:
//! Returns function frame.
inline const FuncFrame& frame() const noexcept { return _frame; }
+ //! Returns function attributes.
+ inline FuncAttributes attributes() const noexcept { return _frame.attributes(); }
+ //! Adds `attrs` to the function attributes.
+ inline void addAttributes(FuncAttributes attrs) noexcept { _frame.addAttributes(attrs); }
+
//! Returns arguments count.
inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
- //! Returns returns count.
- inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); }
+ //! Returns argument packs.
+ inline ArgPack* argPacks() const noexcept { return _args; }
- //! Returns arguments list.
- inline VirtReg** args() const noexcept { return _args; }
+ //! Tests whether the function has a return value.
+ inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
- //! Returns argument at `i`.
- inline VirtReg* arg(uint32_t i) const noexcept {
- ASMJIT_ASSERT(i < argCount());
- return _args[i];
+ //! Returns argument pack at `argIndex`.
+ inline ArgPack& argPack(size_t argIndex) const noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ return _args[argIndex];
}
- //! Sets argument at `i`.
- inline void setArg(uint32_t i, VirtReg* vReg) noexcept {
- ASMJIT_ASSERT(i < argCount());
- _args[i] = vReg;
+ //! Sets argument at `argIndex`.
+ inline void setArg(size_t argIndex, const BaseReg& vReg) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][0].init(vReg);
}
- //! Resets argument at `i`.
- inline void resetArg(uint32_t i) noexcept {
- ASMJIT_ASSERT(i < argCount());
- _args[i] = nullptr;
+ //! \overload
+ inline void setArg(size_t argIndex, const RegOnly& vReg) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][0].init(vReg);
}
- //! Returns function attributes.
- inline uint32_t attributes() const noexcept { return _frame.attributes(); }
- //! Adds `attrs` to the function attributes.
- inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); }
+ //! Sets argument at `argIndex` and `valueIndex`.
+ inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& vReg) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][valueIndex].init(vReg);
+ }
+
+ //! \overload
+ inline void setArg(size_t argIndex, size_t valueIndex, const RegOnly& vReg) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][valueIndex].init(vReg);
+ }
+
+ //! Resets argument pack at `argIndex`.
+ inline void resetArg(size_t argIndex) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex].reset();
+ }
+
+ //! Resets argument pack at `argIndex`.
+ inline void resetArg(size_t argIndex, size_t valueIndex) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][valueIndex].reset();
+ }
//! \}
};
-// ============================================================================
-// [asmjit::FuncRetNode]
-// ============================================================================
-
//! Function return, used by \ref BaseCompiler.
class FuncRetNode : public InstNode {
public:
@@ -670,42 +539,68 @@ public:
//! \{
//! Creates a new `FuncRetNode` instance.
- inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) {
- _any._nodeType = kNodeFuncRet;
+ inline FuncRetNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept : InstNode(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) {
+ _any._nodeType = NodeType::kFuncRet;
}
//! \}
};
-// ============================================================================
-// [asmjit::InvokeNode]
-// ============================================================================
-
//! Function invocation, used by \ref BaseCompiler.
class InvokeNode : public InstNode {
public:
ASMJIT_NONCOPYABLE(InvokeNode)
+ //! Operand pack provides multiple operands that can be associated with a single return value of function
+ //! argument. Sometims this is necessary to express an argument or return value that requires multiple
+ //! registers, for example 64-bit value in 32-bit mode or passing / returning homogeneous data structures.
+ struct OperandPack {
+ //! Operands.
+ Operand_ _data[Globals::kMaxValuePack];
+
+ //! Reset the pack by resetting all operands in the pack.
+ inline void reset() noexcept {
+ for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
+ _data[valueIndex].reset();
+ }
+
+ //! Returns an operand at the given `valueIndex`.
+ inline Operand& operator[](size_t valueIndex) noexcept {
+ ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack);
+ return _data[valueIndex].as<Operand>();
+ }
+
+ //! Returns an operand at the given `valueIndex` (const).
+ const inline Operand& operator[](size_t valueIndex) const noexcept {
+ ASMJIT_ASSERT(valueIndex < Globals::kMaxValuePack);
+ return _data[valueIndex].as<Operand>();
+ }
+ };
+
+ //! \name Members
+ //! \{
+
//! Function detail.
FuncDetail _funcDetail;
- //! Returns.
- Operand_ _rets[2];
- //! Arguments.
- Operand_* _args;
+ //! Function return value(s).
+ OperandPack _rets;
+ //! Function arguments.
+ OperandPack* _args;
+
+ //! \}
//! \name Construction & Destruction
//! \{
//! Creates a new `InvokeNode` instance.
- inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept
+ inline InvokeNode(BaseBuilder* ASMJIT_NONNULL(cb), InstId instId, InstOptions options) noexcept
: InstNode(cb, instId, options, kBaseOpCapacity),
_funcDetail(),
_args(nullptr) {
- setType(kNodeInvoke);
+ setType(NodeType::kInvoke);
_resetOps();
- _rets[0].reset();
- _rets[1].reset();
- addFlags(kFlagIsRemovable);
+ _rets.reset();
+ addFlags(NodeFlags::kIsRemovable);
}
//! \}
@@ -728,53 +623,67 @@ public:
//! \overload
inline const Operand& target() const noexcept { return _opArray[0].as<Operand>(); }
+ //! Returns the number of function return values.
+ inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
//! Returns the number of function arguments.
inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
- //! Returns the number of function return values.
- inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); }
- //! Returns the return value at `i`.
- inline Operand& ret(uint32_t i = 0) noexcept {
- ASMJIT_ASSERT(i < 2);
- return _rets[i].as<Operand>();
+ //! Returns operand pack representing function return value(s).
+ inline OperandPack& retPack() noexcept { return _rets; }
+ //! Returns operand pack representing function return value(s).
+ inline const OperandPack& retPack() const noexcept { return _rets; }
+
+ //! Returns the return value at the given `valueIndex`.
+ inline Operand& ret(size_t valueIndex = 0) noexcept { return _rets[valueIndex]; }
+ //! \overload
+ inline const Operand& ret(size_t valueIndex = 0) const noexcept { return _rets[valueIndex]; }
+
+ //! Returns operand pack representing function return value(s).
+ inline OperandPack& argPack(size_t argIndex) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ return _args[argIndex];
}
//! \overload
- inline const Operand& ret(uint32_t i = 0) const noexcept {
- ASMJIT_ASSERT(i < 2);
- return _rets[i].as<Operand>();
+ inline const OperandPack& argPack(size_t argIndex) const noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ return _args[argIndex];
}
- //! Returns the function argument at `i`.
- inline Operand& arg(uint32_t i) noexcept {
- ASMJIT_ASSERT(i < kFuncArgCountLoHi);
- return _args[i].as<Operand>();
+ //! Returns a function argument at the given `argIndex`.
+ inline Operand& arg(size_t argIndex, size_t valueIndex) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ return _args[argIndex][valueIndex];
}
//! \overload
- inline const Operand& arg(uint32_t i) const noexcept {
- ASMJIT_ASSERT(i < kFuncArgCountLoHi);
- return _args[i].as<Operand>();
+ inline const Operand& arg(size_t argIndex, size_t valueIndex) const noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ return _args[argIndex][valueIndex];
}
- //! Sets the function argument at `i` to `op`.
- ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
//! Sets the function return value at `i` to `op`.
- ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
+ inline void _setRet(size_t valueIndex, const Operand_& op) noexcept { _rets[valueIndex] = op; }
+ //! Sets the function argument at `i` to `op`.
+ inline void _setArg(size_t argIndex, size_t valueIndex, const Operand_& op) noexcept {
+ ASMJIT_ASSERT(argIndex < argCount());
+ _args[argIndex][valueIndex] = op;
+ }
- //! Sets the function argument at `i` to `reg`.
- inline bool setArg(uint32_t i, const BaseReg& reg) noexcept { return _setArg(i, reg); }
- //! Sets the function argument at `i` to `imm`.
- inline bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
+ //! Sets the function return value at `valueIndex` to `reg`.
+ inline void setRet(size_t valueIndex, const BaseReg& reg) noexcept { _setRet(valueIndex, reg); }
- //! Sets the function return value at `i` to `var`.
- inline bool setRet(uint32_t i, const BaseReg& reg) noexcept { return _setRet(i, reg); }
+ //! Sets the first function argument in a value-pack at `argIndex` to `reg`.
+ inline void setArg(size_t argIndex, const BaseReg& reg) noexcept { _setArg(argIndex, 0, reg); }
+ //! Sets the first function argument in a value-pack at `argIndex` to `imm`.
+ inline void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); }
+
+ //! Sets the function argument at `argIndex` and `valueIndex` to `reg`.
+ inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) noexcept { _setArg(argIndex, valueIndex, reg); }
+ //! Sets the function argument at `argIndex` and `valueIndex` to `imm`.
+ inline void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); }
//! \}
};
-// ============================================================================
-// [asmjit::FuncPass]
-// ============================================================================
-
//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction().
class ASMJIT_VIRTAPI FuncPass : public Pass {
public:
@@ -796,7 +705,7 @@ public:
//! \}
- //! \name Run
+ //! \name Pass Interface
//! \{
//! Calls `runOnFunction()` on each `FuncNode` node found.
@@ -808,6 +717,18 @@ public:
//! \}
};
+#if !defined(ASMJIT_NO_DEPRECATED)
+inline Error BaseCompiler::_setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) {
+ FuncNode* func = _func;
+
+ if (ASMJIT_UNLIKELY(!func))
+ return reportError(DebugUtils::errored(kErrorInvalidState));
+
+ func->setArg(argIndex, valueIndex, reg);
+ return kErrorOk;
+}
+#endif
+
//! \}
ASMJIT_END_NAMESPACE