Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifndef __PLUMED_asmjit_codecompiler_h
21 : #define __PLUMED_asmjit_codecompiler_h
22 : #ifdef __PLUMED_HAS_ASMJIT
23 : #pragma GCC diagnostic push
24 : #pragma GCC diagnostic ignored "-Wpedantic"
25 : // [AsmJit]
26 : // Complete x86/x64 JIT and Remote Assembler for C++.
27 : //
28 : // [License]
29 : // Zlib - See LICENSE.md file in the package.
30 :
31 : // [Guard]
32 : #ifndef _ASMJIT_BASE_CODECOMPILER_H
33 : #define _ASMJIT_BASE_CODECOMPILER_H
34 :
35 : #include "./asmjit_build.h"
36 : #if !defined(ASMJIT_DISABLE_COMPILER)
37 :
38 : // [Dependencies]
39 : #include "./assembler.h"
40 : #include "./codebuilder.h"
41 : #include "./constpool.h"
42 : #include "./func.h"
43 : #include "./operand.h"
44 : #include "./utils.h"
45 : #include "./zone.h"
46 :
47 : // [Api-Begin]
48 : #include "./asmjit_apibegin.h"
49 :
50 : namespace PLMD {
51 : namespace asmjit {
52 :
53 : // ============================================================================
54 : // [Forward Declarations]
55 : // ============================================================================
56 :
57 : struct VirtReg;
58 : struct TiedReg;
59 : struct RAState;
60 : struct RACell;
61 :
62 : //! \addtogroup asmjit_base
63 : //! \{
64 :
65 : // ============================================================================
66 : // [asmjit::ConstScope]
67 : // ============================================================================
68 :
69 : //! Scope of the constant.
70 : ASMJIT_ENUM(ConstScope) {
71 : //! Local constant, always embedded right after the current function.
72 : kConstScopeLocal = 0,
73 : //! Global constant, embedded at the end of the currently compiled code.
74 : kConstScopeGlobal = 1
75 : };
76 :
77 : // ============================================================================
78 : // [asmjit::VirtReg]
79 : // ============================================================================
80 :
81 : //! Virtual register data (CodeCompiler).
82 : struct VirtReg {
83 : //! A state of a virtual register (used during register allocation).
84 : ASMJIT_ENUM(State) {
85 : kStateNone = 0, //!< Not allocated, not used.
86 : kStateReg = 1, //!< Allocated in register.
87 : kStateMem = 2 //!< Allocated in memory or spilled.
88 : };
89 :
90 : // --------------------------------------------------------------------------
91 : // [Accessors]
92 : // --------------------------------------------------------------------------
93 :
94 : //! Get the virtual-register id.
95 32168 : ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
96 : //! Get virtual-register's name.
97 0 : ASMJIT_INLINE const char* getName() const noexcept { return _name; }
98 :
99 : //! Get a physical register type.
100 : ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); }
101 : //! Get a physical register kind.
102 : ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); }
103 : //! Get a physical register size.
104 : ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); }
105 : //! Get a register signature of this virtual register.
106 : ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); }
107 :
108 : //! Get a register's type-id, see \ref TypeId.
109 9084 : ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; }
110 :
111 : //! Get virtual-register's size.
112 25856 : ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
113 : //! Get virtual-register's alignment.
114 0 : ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
115 :
116 : //! Get the virtual-register priority, used by compiler to decide which variable to spill.
117 0 : ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; }
118 : //! Set the virtual-register priority.
119 : ASMJIT_INLINE void setPriority(uint32_t priority) noexcept {
120 : ASMJIT_ASSERT(priority <= 0xFF);
121 : _priority = static_cast<uint8_t>(priority);
122 : }
123 :
124 : //! Get variable state, only used by `RAPass`.
125 4972 : ASMJIT_INLINE uint32_t getState() const noexcept { return _state; }
126 : //! Set variable state, only used by `RAPass`.
127 : ASMJIT_INLINE void setState(uint32_t state) {
128 : ASMJIT_ASSERT(state <= 0xFF);
129 0 : _state = static_cast<uint8_t>(state);
130 24694 : }
131 :
132 : //! Get register index.
133 181318 : ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; }
134 : //! Set register index.
135 : ASMJIT_INLINE void setPhysId(uint32_t physId) {
136 : ASMJIT_ASSERT(physId <= Globals::kInvalidRegId);
137 656 : _physId = static_cast<uint8_t>(physId);
138 : }
139 : //! Reset register index.
140 : ASMJIT_INLINE void resetPhysId() {
141 49960 : _physId = static_cast<uint8_t>(Globals::kInvalidRegId);
142 : }
143 :
144 : //! Get home registers mask.
145 26376 : ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; }
146 : //! Add a home register index to the home registers mask.
147 4424 : ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); }
148 :
149 27864 : ASMJIT_INLINE bool isFixed() const noexcept { return static_cast<bool>(_isFixed); }
150 :
151 : //! Get whether the VirtReg is only memory allocated on the stack.
152 10072 : ASMJIT_INLINE bool isStack() const noexcept { return static_cast<bool>(_isStack); }
153 :
154 : //! Get whether to save variable when it's unused (spill).
155 : ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast<bool>(_saveOnUnuse); }
156 :
157 : //! Get whether the variable was changed.
158 10458 : ASMJIT_INLINE bool isModified() const noexcept { return static_cast<bool>(_modified); }
159 : //! Set whether the variable was changed.
160 88716 : ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; }
161 :
162 : //! Get home memory offset.
163 : ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; }
164 : //! Set home memory offset.
165 : ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; }
166 :
167 : //! Get home memory cell.
168 8428 : ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; }
169 : //! Set home memory cell.
170 : ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; }
171 :
172 : // --------------------------------------------------------------------------
173 : // [Members]
174 : // --------------------------------------------------------------------------
175 :
176 : uint32_t _id; //!< Virtual register id.
177 : RegInfo _regInfo; //!< Physical register info & signature.
178 : const char* _name; //!< Virtual name (user provided).
179 : uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`).
180 : uint8_t _typeId; //!< Type-id.
181 : uint8_t _alignment; //!< Register's natural alignment (for spilling).
182 : uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored).
183 : uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated.
184 : uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack.
185 : uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction.
186 : uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope).
187 :
188 : // -------------------------------------------------------------------------
189 : // The following members are used exclusively by RAPass. They are initialized
190 : // when the VirtReg is created and then changed during RAPass.
191 : // -------------------------------------------------------------------------
192 :
193 : uint32_t _raId; //!< Register allocator work-id (used by RAPass).
194 : int32_t _memOffset; //!< Home memory offset.
195 : uint32_t _homeMask; //!< Mask of all registers variable has been allocated to.
196 :
197 : uint8_t _state; //!< Variable state (connected with actual `RAState)`.
198 : uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate.
199 : uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`.
200 :
201 : RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr).
202 :
203 : //! Temporary link to TiedReg* used by the `RAPass` used in
204 : //! various phases, but always set back to nullptr when finished.
205 : //!
206 : //! This temporary data is designed to be used by algorithms that need to
207 : //! store some data into variables themselves during compilation. But it's
208 : //! expected that after variable is compiled & translated the data is set
209 : //! back to zero/null. Initial value is nullptr.
210 : TiedReg* _tied;
211 : };
212 :
213 : // ============================================================================
214 : // [asmjit::CCHint]
215 : // ============================================================================
216 :
217 : //! Hint for register allocator (CodeCompiler).
218 : class CCHint : public CBNode {
219 : public:
220 : ASMJIT_NONCOPYABLE(CCHint)
221 :
222 : //! Hint type.
223 : ASMJIT_ENUM(Hint) {
224 : //! Alloc to physical reg.
225 : kHintAlloc = 0,
226 : //! Spill to memory.
227 : kHintSpill = 1,
228 : //! Save if modified.
229 : kHintSave = 2,
230 : //! Save if modified and mark it as unused.
231 : kHintSaveAndUnuse = 3,
232 : //! Mark as unused.
233 : kHintUnuse = 4
234 : };
235 :
236 : // --------------------------------------------------------------------------
237 : // [Construction / Destruction]
238 : // --------------------------------------------------------------------------
239 :
240 : //! Create a new `CCHint` instance.
241 0 : ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) {
242 : orFlags(kFlagIsRemovable | kFlagIsInformative);
243 0 : _vreg = vreg;
244 0 : _hint = hint;
245 0 : _value = value;
246 : }
247 :
248 : //! Destroy the `CCHint` instance (NEVER CALLED).
249 : ASMJIT_INLINE ~CCHint() noexcept {}
250 :
251 : // --------------------------------------------------------------------------
252 : // [Accessors]
253 : // --------------------------------------------------------------------------
254 :
255 : //! Get variable.
256 0 : ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; }
257 :
258 : //! Get hint it, see \ref Hint.
259 0 : ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; }
260 : //! Set hint it, see \ref Hint.
261 : ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; }
262 :
263 : //! Get hint value.
264 0 : ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; }
265 : //! Set hint value.
266 : ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; }
267 :
268 : // --------------------------------------------------------------------------
269 : // [Members]
270 : // --------------------------------------------------------------------------
271 :
272 : //! Variable.
273 : VirtReg* _vreg;
274 : //! Hint id.
275 : uint32_t _hint;
276 : //! Value.
277 : uint32_t _value;
278 : };
279 :
280 : // ============================================================================
281 : // [asmjit::CCFunc]
282 : // ============================================================================
283 :
284 : //! Function entry (CodeCompiler).
285 : class CCFunc : public CBLabel {
286 : public:
287 : ASMJIT_NONCOPYABLE(CCFunc)
288 :
289 : // --------------------------------------------------------------------------
290 : // [Construction / Destruction]
291 : // --------------------------------------------------------------------------
292 :
293 : //! Create a new `CCFunc` instance.
294 : //!
295 : //! Always use `CodeCompiler::addFunc()` to create \ref CCFunc.
296 : ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept
297 1944 : : CBLabel(cb),
298 1944 : _funcDetail(),
299 1944 : _frameInfo(),
300 1944 : _exitNode(nullptr),
301 1944 : _end(nullptr),
302 1944 : _args(nullptr),
303 1944 : _isFinished(false) {
304 :
305 1944 : _type = kNodeFunc;
306 : }
307 :
308 : //! Destroy the `CCFunc` instance (NEVER CALLED).
309 : ASMJIT_INLINE ~CCFunc() noexcept {}
310 :
311 : // --------------------------------------------------------------------------
312 : // [Accessors]
313 : // --------------------------------------------------------------------------
314 :
315 : //! Get function exit `CBLabel`.
316 7776 : ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; }
317 : //! Get function exit label.
318 : ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); }
319 :
320 : //! Get "End of Func" sentinel.
321 7776 : ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; }
322 :
323 : //! Get function declaration.
324 1944 : ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
325 : //! Get function declaration.
326 0 : ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
327 :
328 : //! Get function declaration.
329 1944 : ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; }
330 : //! Get function declaration.
331 : ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; }
332 :
333 : //! Get arguments count.
334 : ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); }
335 : //! Get returns count.
336 : ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); }
337 :
338 : //! Get arguments list.
339 0 : ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; }
340 :
341 : //! Get argument at `i`.
342 : ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept {
343 : ASMJIT_ASSERT(i < getArgCount());
344 0 : return _args[i];
345 : }
346 :
347 : //! Set argument at `i`.
348 : ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept {
349 : ASMJIT_ASSERT(i < getArgCount());
350 0 : _args[i] = vreg;
351 : }
352 :
353 : //! Reset argument at `i`.
354 : ASMJIT_INLINE void resetArg(uint32_t i) noexcept {
355 : ASMJIT_ASSERT(i < getArgCount());
356 : _args[i] = nullptr;
357 : }
358 :
359 : ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); }
360 : ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); }
361 :
362 : // --------------------------------------------------------------------------
363 : // [Members]
364 : // --------------------------------------------------------------------------
365 :
366 : FuncDetail _funcDetail; //!< Function detail.
367 : FuncFrameInfo _frameInfo; //!< Function frame information.
368 :
369 : CBLabel* _exitNode; //!< Function exit.
370 : CBSentinel* _end; //!< Function end.
371 :
372 : VirtReg** _args; //!< Arguments array as `VirtReg`.
373 :
374 : //! Function was finished by `Compiler::endFunc()`.
375 : uint8_t _isFinished;
376 : };
377 :
378 : // ============================================================================
379 : // [asmjit::CCFuncRet]
380 : // ============================================================================
381 :
382 : //! Function return (CodeCompiler).
383 : class CCFuncRet : public CBNode {
384 : public:
385 : ASMJIT_NONCOPYABLE(CCFuncRet)
386 :
387 : // --------------------------------------------------------------------------
388 : // [Construction / Destruction]
389 : // --------------------------------------------------------------------------
390 :
391 : //! Create a new `CCFuncRet` instance.
392 1944 : ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) {
393 : orFlags(kFlagIsRet);
394 1944 : _ret[0].copyFrom(o0);
395 1944 : _ret[1].copyFrom(o1);
396 : }
397 :
398 : //! Destroy the `CCFuncRet` instance (NEVER CALLED).
399 : ASMJIT_INLINE ~CCFuncRet() noexcept {}
400 :
401 : // --------------------------------------------------------------------------
402 : // [Accessors]
403 : // --------------------------------------------------------------------------
404 :
405 : //! Get the first return operand.
406 : ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast<Operand&>(_ret[0]); }
407 : //! \overload
408 : ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast<const Operand&>(_ret[0]); }
409 :
410 : //! Get the second return operand.
411 : ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast<Operand&>(_ret[1]); }
412 : //! \overload
413 : ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast<const Operand&>(_ret[1]); }
414 :
415 : // --------------------------------------------------------------------------
416 : // [Members]
417 : // --------------------------------------------------------------------------
418 :
419 : //! Return operands.
420 : Operand_ _ret[2];
421 : };
422 :
423 : // ============================================================================
424 : // [asmjit::CCFuncCall]
425 : // ============================================================================
426 :
427 : //! Function call (CodeCompiler).
428 : class CCFuncCall : public CBInst {
429 : public:
430 : ASMJIT_NONCOPYABLE(CCFuncCall)
431 :
432 : // --------------------------------------------------------------------------
433 : // [Construction / Destruction]
434 : // --------------------------------------------------------------------------
435 :
436 : //! Create a new `CCFuncCall` instance.
437 : ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
438 1636 : : CBInst(cb, instId, options, opArray, opCount),
439 1636 : _funcDetail(),
440 1636 : _args(nullptr) {
441 :
442 1636 : _type = kNodeFuncCall;
443 : _ret[0].reset();
444 : _ret[1].reset();
445 : orFlags(kFlagIsRemovable);
446 : }
447 :
448 : //! Destroy the `CCFuncCall` instance (NEVER CALLED).
449 : ASMJIT_INLINE ~CCFuncCall() noexcept {}
450 :
451 : // --------------------------------------------------------------------------
452 : // [Signature]
453 : // --------------------------------------------------------------------------
454 :
455 : //! Set function signature.
456 : ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept {
457 : return _funcDetail.init(sign);
458 : }
459 :
460 : // --------------------------------------------------------------------------
461 : // [Accessors]
462 : // --------------------------------------------------------------------------
463 :
464 : //! Get function declaration.
465 : ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
466 : //! Get function declaration.
467 : ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
468 :
469 : //! Get target operand.
470 : ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast<Operand&>(_opArray[0]); }
471 : //! \overload
472 : ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast<const Operand&>(_opArray[0]); }
473 :
474 : //! Get return at `i`.
475 : ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept {
476 : ASMJIT_ASSERT(i < 2);
477 : return static_cast<Operand&>(_ret[i]);
478 : }
479 : //! \overload
480 : ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept {
481 : ASMJIT_ASSERT(i < 2);
482 : return static_cast<const Operand&>(_ret[i]);
483 : }
484 :
485 : //! Get argument at `i`.
486 : ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept {
487 : ASMJIT_ASSERT(i < kFuncArgCountLoHi);
488 : return static_cast<Operand&>(_args[i]);
489 : }
490 : //! \overload
491 : ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept {
492 : ASMJIT_ASSERT(i < kFuncArgCountLoHi);
493 : return static_cast<const Operand&>(_args[i]);
494 : }
495 :
496 : //! Set argument at `i` to `op`.
497 : ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
498 : //! Set return at `i` to `op`.
499 : ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
500 :
501 : //! Set argument at `i` to `reg`.
502 1434 : ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); }
503 : //! Set argument at `i` to `imm`.
504 202 : ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
505 :
506 : //! Set return at `i` to `var`.
507 1636 : ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); }
508 :
509 : // --------------------------------------------------------------------------
510 : // [Members]
511 : // --------------------------------------------------------------------------
512 :
513 : FuncDetail _funcDetail; //!< Function detail.
514 : Operand_ _ret[2]; //!< Return.
515 : Operand_* _args; //!< Arguments.
516 : };
517 :
518 : // ============================================================================
519 : // [asmjit::CCPushArg]
520 : // ============================================================================
521 :
522 : //! Push argument before a function call (CodeCompiler).
523 : class CCPushArg : public CBNode {
524 : public:
525 : ASMJIT_NONCOPYABLE(CCPushArg)
526 :
527 : // --------------------------------------------------------------------------
528 : // [Construction / Destruction]
529 : // --------------------------------------------------------------------------
530 :
531 : //! Create a new `CCPushArg` instance.
532 : ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept
533 0 : : CBNode(cb, kNodePushArg),
534 0 : _call(call),
535 0 : _src(src),
536 0 : _cvt(cvt),
537 0 : _args(0) {
538 : orFlags(kFlagIsRemovable);
539 : }
540 :
541 : //! Destroy the `CCPushArg` instance.
542 : ASMJIT_INLINE ~CCPushArg() noexcept {}
543 :
544 : // --------------------------------------------------------------------------
545 : // [Accessors]
546 : // --------------------------------------------------------------------------
547 :
548 : //! Get the associated function-call.
549 0 : ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; }
550 : //! Get source variable.
551 0 : ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; }
552 : //! Get conversion variable.
553 0 : ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; }
554 :
555 : // --------------------------------------------------------------------------
556 : // [Members]
557 : // --------------------------------------------------------------------------
558 :
559 : CCFuncCall* _call; //!< Associated `CCFuncCall`.
560 : VirtReg* _src; //!< Source variable.
561 : VirtReg* _cvt; //!< Temporary variable used for conversion (or null).
562 : uint32_t _args; //!< Affected arguments bit-array.
563 : };
564 :
565 : // ============================================================================
566 : // [asmjit::CodeCompiler]
567 : // ============================================================================
568 :
569 : //! Code emitter that uses virtual registers and performs register allocation.
570 : //!
571 : //! Compiler is a high-level code-generation tool that provides register
572 : //! allocation and automatic handling of function calling conventions. It was
573 : //! primarily designed for merging multiple parts of code into a function
574 : //! without worrying about registers and function calling conventions.
575 : //!
576 : //! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit
577 : //! code at the same time.
578 : //!
579 : //! CodeCompiler is based on CodeBuilder and contains all the features it
580 : //! provides. It means that the code it stores can be modified (removed, added,
581 : //! injected) and analyzed. When the code is finalized the compiler can emit
582 : //! the code into an Assembler to translate the abstract representation into a
583 : //! machine code.
584 : class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder {
585 : public:
586 : ASMJIT_NONCOPYABLE(CodeCompiler)
587 : typedef CodeBuilder Base;
588 :
589 : // --------------------------------------------------------------------------
590 : // [Construction / Destruction]
591 : // --------------------------------------------------------------------------
592 :
593 : //! Create a new `CodeCompiler` instance.
594 : ASMJIT_API CodeCompiler() noexcept;
595 : //! Destroy the `CodeCompiler` instance.
596 : ASMJIT_API virtual ~CodeCompiler() noexcept;
597 :
598 : // --------------------------------------------------------------------------
599 : // [Events]
600 : // --------------------------------------------------------------------------
601 :
602 : ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
603 : ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
604 :
605 : // --------------------------------------------------------------------------
606 : // [Node-Factory]
607 : // --------------------------------------------------------------------------
608 :
609 : //! \internal
610 : //!
611 : //! Create a new `CCHint`.
612 : ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept;
613 :
614 : // --------------------------------------------------------------------------
615 : // [Func]
616 : // --------------------------------------------------------------------------
617 :
618 : //! Get the current function.
619 1944 : ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; }
620 :
621 : //! Create a new `CCFunc`.
622 : ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept;
623 : //! Add a function `node` to the stream.
624 : ASMJIT_API CCFunc* addFunc(CCFunc* func);
625 : //! Add a new function.
626 : ASMJIT_API CCFunc* addFunc(const FuncSignature& sign);
627 : //! Emit a sentinel that marks the end of the current function.
628 : ASMJIT_API CBSentinel* endFunc();
629 :
630 : // --------------------------------------------------------------------------
631 : // [Ret]
632 : // --------------------------------------------------------------------------
633 :
634 : //! Create a new `CCFuncRet`.
635 : ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept;
636 : //! Add a new `CCFuncRet`.
637 : ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept;
638 :
639 : // --------------------------------------------------------------------------
640 : // [Call]
641 : // --------------------------------------------------------------------------
642 :
643 : //! Create a new `CCFuncCall`.
644 : ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
645 : //! Add a new `CCFuncCall`.
646 : ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
647 :
648 : // --------------------------------------------------------------------------
649 : // [Args]
650 : // --------------------------------------------------------------------------
651 :
652 : //! Set a function argument at `argIndex` to `reg`.
653 : ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg);
654 :
655 : // --------------------------------------------------------------------------
656 : // [Hint]
657 : // --------------------------------------------------------------------------
658 :
659 : //! Emit a new hint (purely informational node).
660 : ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value);
661 :
662 : // --------------------------------------------------------------------------
663 : // [VirtReg / Stack]
664 : // --------------------------------------------------------------------------
665 :
666 : //! Create a new virtual register representing the given `vti` and `signature`.
667 : //!
668 : //! This function accepts either register type representing a machine-specific
669 : //! register, like `X86Reg`, or RegTag representation, which represents
670 : //! machine independent register, and from the machine-specific register
671 : //! is deduced.
672 : ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept;
673 :
674 : ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name);
675 : ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap);
676 :
677 : ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name);
678 : ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap);
679 :
680 : ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name);
681 : ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size);
682 :
683 : // --------------------------------------------------------------------------
684 : // [VirtReg]
685 : // --------------------------------------------------------------------------
686 :
687 : //! Get whether the virtual register `r` is valid.
688 : ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept {
689 : return isVirtRegValid(reg.getId());
690 : }
691 : //! \overload
692 : ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept {
693 12136 : size_t index = Operand::unpackId(id);
694 : return index < _vRegArray.getLength();
695 : }
696 :
697 : //! Get \ref VirtReg associated with the given `r`.
698 : ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept {
699 : return getVirtRegById(reg.getId());
700 : }
701 : //! Get \ref VirtReg associated with the given `id`.
702 : ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept {
703 : ASMJIT_ASSERT(id != kInvalidValue);
704 116154 : size_t index = Operand::unpackId(id);
705 :
706 : ASMJIT_ASSERT(index < _vRegArray.getLength());
707 128290 : return _vRegArray[index];
708 : }
709 :
710 : //! Get an array of all virtual registers managed by CodeCompiler.
711 : ASMJIT_INLINE const ZoneVector<VirtReg*>& getVirtRegArray() const noexcept { return _vRegArray; }
712 :
713 : //! Alloc a virtual register `reg`.
714 : ASMJIT_API Error alloc(Reg& reg);
715 : //! Alloc a virtual register `reg` using `physId` as a register id.
716 : ASMJIT_API Error alloc(Reg& reg, uint32_t physId);
717 : //! Alloc a virtual register `reg` using `ref` as a register operand.
718 : ASMJIT_API Error alloc(Reg& reg, const Reg& ref);
719 : //! Spill a virtual register `reg`.
720 : ASMJIT_API Error spill(Reg& reg);
721 : //! Save a virtual register `reg` if the status is `modified` at this point.
722 : ASMJIT_API Error save(Reg& reg);
723 : //! Unuse a virtual register `reg`.
724 : ASMJIT_API Error unuse(Reg& reg);
725 :
726 : //! Get priority of a virtual register `reg`.
727 : ASMJIT_API uint32_t getPriority(Reg& reg) const;
728 : //! Set priority of variable `reg` to `priority`.
729 : ASMJIT_API void setPriority(Reg& reg, uint32_t priority);
730 :
731 : //! Get save-on-unuse `reg` property.
732 : ASMJIT_API bool getSaveOnUnuse(Reg& reg) const;
733 : //! Set save-on-unuse `reg` property to `value`.
734 : ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value);
735 :
736 : //! Rename variable `reg` to `name`.
737 : //!
738 : //! NOTE: Only new name will appear in the logger.
739 : ASMJIT_API void rename(Reg& reg, const char* fmt, ...);
740 :
741 : // --------------------------------------------------------------------------
742 : // [Members]
743 : // --------------------------------------------------------------------------
744 :
745 : CCFunc* _func; //!< Current function.
746 :
747 : Zone _vRegZone; //!< Allocates \ref VirtReg objects.
748 : ZoneVector<VirtReg*> _vRegArray; //!< Stores array of \ref VirtReg pointers.
749 :
750 : CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function.
751 : CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation.
752 : };
753 :
754 : //! \}
755 :
756 : } // asmjit namespace
757 : } // namespace PLMD
758 :
759 : // [Api-End]
760 : #include "./asmjit_apiend.h"
761 :
762 : // [Guard]
763 : #endif // !ASMJIT_DISABLE_COMPILER
764 : #endif // _ASMJIT_BASE_CODECOMPILER_H
765 : #pragma GCC diagnostic pop
766 : #endif // __PLUMED_HAS_ASMJIT
767 : #endif
|