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
|