1 // [AsmJit]
2 // Machine Code Generation for C++.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6 
7 #ifndef _ASMJIT_CORE_COMPILER_H
8 #define _ASMJIT_CORE_COMPILER_H
9 
10 #include "../core/build.h"
11 #ifndef ASMJIT_NO_COMPILER
12 
13 #include "../core/assembler.h"
14 #include "../core/builder.h"
15 #include "../core/constpool.h"
16 #include "../core/func.h"
17 #include "../core/inst.h"
18 #include "../core/operand.h"
19 #include "../core/support.h"
20 #include "../core/zone.h"
21 #include "../core/zonevector.h"
22 
23 ASMJIT_BEGIN_NAMESPACE
24 
25 // ============================================================================
26 // [Forward Declarations]
27 // ============================================================================
28 
29 struct RATiedReg;
30 class RAWorkReg;
31 
32 class FuncNode;
33 class FuncRetNode;
34 class FuncCallNode;
35 
36 //! \addtogroup asmjit_compiler
37 //! \{
38 
39 // ============================================================================
40 // [asmjit::VirtReg]
41 // ============================================================================
42 
43 //! Virtual register data (BaseCompiler).
44 class VirtReg {
45 public:
46   ASMJIT_NONCOPYABLE(VirtReg)
47 
48   //! Virtual register id.
49   uint32_t _id;
50   //! Virtual register info (signature).
51   RegInfo _info;
52   //! Virtual register size (can be smaller than `regInfo._size`).
53   uint32_t _virtSize;
54   //! Virtual register alignment (for spilling).
55   uint8_t _alignment;
56   //! Type-id.
57   uint8_t _typeId;
58   //! Virtual register weight for alloc/spill decisions.
59   uint8_t _weight;
60   //! True if this is a fixed register, never reallocated.
61   uint8_t _isFixed : 1;
62   //! True if the virtual register is only used as a stack (never accessed as register).
63   uint8_t _isStack : 1;
64   uint8_t _reserved : 6;
65 
66   //! Virtual register name (user provided or automatically generated).
67   ZoneString<16> _name;
68 
69   // -------------------------------------------------------------------------
70   // The following members are used exclusively by RAPass. They are initialized
71   // when the VirtReg is created to NULL pointers and then changed during RAPass
72   // execution. RAPass sets them back to NULL before it returns.
73   // -------------------------------------------------------------------------
74 
75   //! Reference to `RAWorkReg`, used during register allocation.
76   RAWorkReg* _workReg;
77 
78   //! \name Construction & Destruction
79   //! \{
80 
VirtReg(uint32_t id,uint32_t signature,uint32_t virtSize,uint32_t alignment,uint32_t typeId)81   inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept
82     : _id(id),
83       _virtSize(virtSize),
84       _alignment(uint8_t(alignment)),
85       _typeId(uint8_t(typeId)),
86       _weight(1),
87       _isFixed(false),
88       _isStack(false),
89       _reserved(0),
90       _name(),
91       _workReg(nullptr) { _info._signature = signature; }
92 
93   //! \}
94 
95   //! \name Accessors
96   //! \{
97 
98   //! Returns the virtual register id.
id()99   inline uint32_t id() const noexcept { return _id; }
100 
101   //! Returns the virtual register name.
name()102   inline const char* name() const noexcept { return _name.data(); }
103   //! Returns the size of the virtual register name.
nameSize()104   inline uint32_t nameSize() const noexcept { return _name.size(); }
105 
106   //! Returns a register information that wraps the register signature.
info()107   inline const RegInfo& info() const noexcept { return _info; }
108   //! Returns a virtual register type (maps to the physical register type as well).
type()109   inline uint32_t type() const noexcept { return _info.type(); }
110   //! Returns a virtual register group (maps to the physical register group as well).
group()111   inline uint32_t group() const noexcept { return _info.group(); }
112 
113   //! Returns a real size of the register this virtual register maps to.
114   //!
115   //! For example if this is a 128-bit SIMD register used for a scalar single
116   //! precision floating point value then its virtSize would be 4, however, the
117   //! `regSize` would still say 16 (128-bits), because it's the smallest size
118   //! of that register type.
regSize()119   inline uint32_t regSize() const noexcept { return _info.size(); }
120 
121   //! Returns a register signature of this virtual register.
signature()122   inline uint32_t signature() const noexcept { return _info.signature(); }
123 
124   //! Returns the virtual register size.
125   //!
126   //! The virtual register size describes how many bytes the virtual register
127   //! needs to store its content. It can be smaller than the physical register
128   //! size, see `regSize()`.
virtSize()129   inline uint32_t virtSize() const noexcept { return _virtSize; }
130 
131   //! Returns the virtual register alignment.
alignment()132   inline uint32_t alignment() const noexcept { return _alignment; }
133 
134   //! Returns the virtual register type id, see `Type::Id`.
typeId()135   inline uint32_t typeId() const noexcept { return _typeId; }
136 
137   //! Returns the virtual register weight - the register allocator can use it
138   //! as explicit hint for alloc/spill decisions.
weight()139   inline uint32_t weight() const noexcept { return _weight; }
140   //! Sets the virtual register weight (0 to 255) - the register allocator can
141   //! use it as explicit hint for alloc/spill decisions and initial bin-packing.
setWeight(uint32_t weight)142   inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); }
143 
144   //! Returns whether the virtual register is always allocated to a fixed
145   //! physical register (and never reallocated).
146   //!
147   //! \note This is only used for special purposes and it's mostly internal.
isFixed()148   inline bool isFixed() const noexcept { return bool(_isFixed); }
149 
150   //! Returns whether the virtual register is indeed a stack that only uses
151   //! the virtual register id for making it accessible.
152   //!
153   //! \note It's an error if a stack is accessed as a register.
isStack()154   inline bool isStack() const noexcept { return bool(_isStack); }
155 
hasWorkReg()156   inline bool hasWorkReg() const noexcept { return _workReg != nullptr; }
workReg()157   inline RAWorkReg* workReg() const noexcept { return _workReg; }
setWorkReg(RAWorkReg * workReg)158   inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; }
resetWorkReg()159   inline void resetWorkReg() noexcept { _workReg = nullptr; }
160 
161   //! \}
162 };
163 
164 // ============================================================================
165 // [asmjit::BaseCompiler]
166 // ============================================================================
167 
168 //! Code emitter that uses virtual registers and performs register allocation.
169 //!
170 //! Compiler is a high-level code-generation tool that provides register
171 //! allocation and automatic handling of function calling conventions. It was
172 //! primarily designed for merging multiple parts of code into a function
173 //! without worrying about registers and function calling conventions.
174 //!
175 //! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit
176 //! code at the same time.
177 //!
178 //! BaseCompiler is based on BaseBuilder and contains all the features it
179 //! provides. It means that the code it stores can be modified (removed, added,
180 //! injected) and analyzed. When the code is finalized the compiler can emit
181 //! the code into an Assembler to translate the abstract representation into a
182 //! machine code.
183 class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder {
184 public:
185   ASMJIT_NONCOPYABLE(BaseCompiler)
186   typedef BaseBuilder Base;
187 
188   //! Current function.
189   FuncNode* _func;
190   //! Allocates `VirtReg` objects.
191   Zone _vRegZone;
192   //! Stores array of `VirtReg` pointers.
193   ZoneVector<VirtReg*> _vRegArray;
194 
195   //! Local constant pool, flushed at the end of each function.
196   ConstPoolNode* _localConstPool;
197   //! Global constant pool, flushed by `finalize()`.
198   ConstPoolNode* _globalConstPool;
199 
200   //! \name Construction & Destruction
201   //! \{
202 
203   //! Creates a new `BaseCompiler` instance.
204   ASMJIT_API BaseCompiler() noexcept;
205   //! Destroys the `BaseCompiler` instance.
206   ASMJIT_API virtual ~BaseCompiler() noexcept;
207 
208   //! \}
209 
210   //! \name Function API
211   //! \{
212 
213   //! Returns the current function.
func()214   inline FuncNode* func() const noexcept { return _func; }
215 
216   //! Creates a new `FuncNode`.
217   ASMJIT_API FuncNode* newFunc(const FuncSignature& sign) noexcept;
218   //! Adds a function `node` to the stream.
219   ASMJIT_API FuncNode* addFunc(FuncNode* func);
220   //! Adds a new function.
221   ASMJIT_API FuncNode* addFunc(const FuncSignature& sign);
222   //! Emits a sentinel that marks the end of the current function.
223   ASMJIT_API Error endFunc();
224 
225   //! Sets a function argument at `argIndex` to `reg`.
226   ASMJIT_API Error setArg(uint32_t argIndex, const BaseReg& reg);
227 
228   //! Creates a new `FuncRetNode`.
229   ASMJIT_API FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) noexcept;
230   //! Adds a new `FuncRetNode`.
231   ASMJIT_API FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) noexcept;
232 
233   //! \}
234 
235   //! \name Function Calls
236   //! \{
237 
238   //! Creates a new `FuncCallNode`.
239   ASMJIT_API FuncCallNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
240   //! Adds a new `FuncCallNode`.
241   ASMJIT_API FuncCallNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
242 
243   //! \}
244 
245   //! \name Virtual Registers
246   //! \{
247 
248   //! Creates a new virtual register representing the given `typeId` and `signature`.
249   ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept;
250 
251   ASMJIT_API Error _newReg(BaseReg& out, uint32_t typeId, const char* name = nullptr);
252   ASMJIT_API Error _newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...);
253 
254   ASMJIT_API Error _newReg(BaseReg& out, const BaseReg& ref, const char* name = nullptr);
255   ASMJIT_API Error _newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...);
256 
257   //! Tests whether the given `id` is a valid virtual register id.
isVirtIdValid(uint32_t id)258   inline bool isVirtIdValid(uint32_t id) const noexcept {
259     uint32_t index = Operand::virtIdToIndex(id);
260     return index < _vRegArray.size();
261   }
262   //! Tests whether the given `reg` is a virtual register having a valid id.
isVirtRegValid(const BaseReg & reg)263   inline bool isVirtRegValid(const BaseReg& reg) const noexcept {
264     return isVirtIdValid(reg.id());
265   }
266 
267   //! Returns `VirtReg` associated with the given `id`.
virtRegById(uint32_t id)268   inline VirtReg* virtRegById(uint32_t id) const noexcept {
269     ASMJIT_ASSERT(isVirtIdValid(id));
270     return _vRegArray[Operand::virtIdToIndex(id)];
271   }
272   //! Returns `VirtReg` associated with the given `reg`.
virtRegByReg(const BaseReg & reg)273   inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); }
274   //! Returns `VirtReg` associated with the given `index`.
virtRegByIndex(uint32_t index)275   inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
276 
277   //! Returns an array of all virtual registers managed by the Compiler.
virtRegs()278   inline const ZoneVector<VirtReg*>& virtRegs() const noexcept { return _vRegArray; }
279 
280   //! \name Stack
281   //! \{
282 
283   ASMJIT_API Error _newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name = nullptr);
284 
285   //! \}
286 
287   //! \name Constants
288   //! \{
289 
290   ASMJIT_API Error _newConst(BaseMem& out, uint32_t scope, const void* data, size_t size);
291 
292   //! \}
293 
294   //! \name Miscellaneous
295   //! \{
296 
297   //! Rename the given virtual register `reg` to a formatted string `fmt`.
298   //!
299   //! \note Only new name will appear in the logger.
300   ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...);
301 
302   //! \}
303 
304   // TODO: These should be removed
alloc(BaseReg & reg)305   inline void alloc(BaseReg& reg) { ASMJIT_UNUSED(reg); }
spill(BaseReg & reg)306   inline void spill(BaseReg& reg) { ASMJIT_UNUSED(reg); }
307 
308   //! \name Events
309   //! \{
310 
311   ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
312   ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
313 
314   //! \}
315 };
316 
317 // ============================================================================
318 // [asmjit::FuncNode]
319 // ============================================================================
320 
321 //! Function entry (BaseCompiler).
322 class FuncNode : public LabelNode {
323 public:
324   ASMJIT_NONCOPYABLE(FuncNode)
325 
326   //! Function detail.
327   FuncDetail _funcDetail;
328   //! Function frame.
329   FuncFrame _frame;
330   //! Function exit (label).
331   LabelNode* _exitNode;
332   //! Function end (sentinel).
333   SentinelNode* _end;
334   //! Arguments array as `VirtReg`.
335   VirtReg** _args;
336 
337   //! \name Construction & Destruction
338   //! \{
339 
340   //! Creates a new `FuncNode` instance.
341   //!
342   //! Always use `BaseCompiler::addFunc()` to create `FuncNode`.
FuncNode(BaseBuilder * cb)343   ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept
344     : LabelNode(cb),
345       _funcDetail(),
346       _frame(),
347       _exitNode(nullptr),
348       _end(nullptr),
349       _args(nullptr) {
350     setType(kNodeFunc);
351   }
352 
353   //! \}
354 
355   //! \{
356   //! \name Accessors
357 
358   //! Returns function exit `LabelNode`.
exitNode()359   inline LabelNode* exitNode() const noexcept { return _exitNode; }
360   //! Returns function exit label.
exitLabel()361   inline Label exitLabel() const noexcept { return _exitNode->label(); }
362 
363   //! Returns "End of Func" sentinel.
endNode()364   inline SentinelNode* endNode() const noexcept { return _end; }
365 
366   //! Returns function declaration.
detail()367   inline FuncDetail& detail() noexcept { return _funcDetail; }
368   //! Returns function declaration.
detail()369   inline const FuncDetail& detail() const noexcept { return _funcDetail; }
370 
371   //! Returns function frame.
frame()372   inline FuncFrame& frame() noexcept { return _frame; }
373   //! Returns function frame.
frame()374   inline const FuncFrame& frame() const noexcept { return _frame; }
375 
376   //! Returns arguments count.
argCount()377   inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
378   //! Returns returns count.
retCount()379   inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); }
380 
381   //! Returns arguments list.
args()382   inline VirtReg** args() const noexcept { return _args; }
383 
384   //! Returns argument at `i`.
arg(uint32_t i)385   inline VirtReg* arg(uint32_t i) const noexcept {
386     ASMJIT_ASSERT(i < argCount());
387     return _args[i];
388   }
389 
390   //! Sets argument at `i`.
setArg(uint32_t i,VirtReg * vReg)391   inline void setArg(uint32_t i, VirtReg* vReg) noexcept {
392     ASMJIT_ASSERT(i < argCount());
393     _args[i] = vReg;
394   }
395 
396   //! Resets argument at `i`.
resetArg(uint32_t i)397   inline void resetArg(uint32_t i) noexcept {
398     ASMJIT_ASSERT(i < argCount());
399     _args[i] = nullptr;
400   }
401 
attributes()402   inline uint32_t attributes() const noexcept { return _frame.attributes(); }
addAttributes(uint32_t attrs)403   inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); }
404 
405   //! \}
406 };
407 
408 // ============================================================================
409 // [asmjit::FuncRetNode]
410 // ============================================================================
411 
412 //! Function return (BaseCompiler).
413 class FuncRetNode : public InstNode {
414 public:
ASMJIT_NONCOPYABLE(FuncRetNode)415   ASMJIT_NONCOPYABLE(FuncRetNode)
416 
417   //! \name Construction & Destruction
418   //! \{
419 
420   //! Creates a new `FuncRetNode` instance.
421   inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) {
422     _any._nodeType = kNodeFuncRet;
423   }
424 
425   //! \}
426 };
427 
428 // ============================================================================
429 // [asmjit::FuncCallNode]
430 // ============================================================================
431 
432 //! Function call (BaseCompiler).
433 class FuncCallNode : public InstNode {
434 public:
435   ASMJIT_NONCOPYABLE(FuncCallNode)
436 
437   //! Function detail.
438   FuncDetail _funcDetail;
439   //! Returns.
440   Operand_ _rets[2];
441   //! Arguments.
442   Operand_* _args;
443 
444   //! \name Construction & Destruction
445   //! \{
446 
447   //! Creates a new `FuncCallNode` instance.
FuncCallNode(BaseBuilder * cb,uint32_t instId,uint32_t options)448   inline FuncCallNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept
449     : InstNode(cb, instId, options, kBaseOpCapacity),
450       _funcDetail(),
451       _args(nullptr) {
452     setType(kNodeFuncCall);
453     _resetOps();
454     _rets[0].reset();
455     _rets[1].reset();
456     addFlags(kFlagIsRemovable);
457   }
458 
459   //! \}
460 
461   //! \name Accessors
462   //! \{
463 
464   //! Sets the function signature.
setSignature(const FuncSignature & sign)465   inline Error setSignature(const FuncSignature& sign) noexcept {
466     return _funcDetail.init(sign);
467   }
468 
469   //! Returns the function detail.
detail()470   inline FuncDetail& detail() noexcept { return _funcDetail; }
471   //! Returns the function detail.
detail()472   inline const FuncDetail& detail() const noexcept { return _funcDetail; }
473 
474   //! Returns the target operand.
target()475   inline Operand& target() noexcept { return _opArray[0].as<Operand>(); }
476   //! \overload
target()477   inline const Operand& target() const noexcept { return _opArray[0].as<Operand>(); }
478 
479   //! Returns the number of function arguments.
argCount()480   inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
481   //! Returns the number of function return values.
retCount()482   inline uint32_t retCount() const noexcept { return _funcDetail.retCount(); }
483 
484   //! Returns the return value at `i`.
485   inline Operand& ret(uint32_t i = 0) noexcept {
486     ASMJIT_ASSERT(i < 2);
487     return _rets[i].as<Operand>();
488   }
489   //! \overload
490   inline const Operand& ret(uint32_t i = 0) const noexcept {
491     ASMJIT_ASSERT(i < 2);
492     return _rets[i].as<Operand>();
493   }
494 
495   //! Returns the function argument at `i`.
arg(uint32_t i)496   inline Operand& arg(uint32_t i) noexcept {
497     ASMJIT_ASSERT(i < kFuncArgCountLoHi);
498     return _args[i].as<Operand>();
499   }
500   //! \overload
arg(uint32_t i)501   inline const Operand& arg(uint32_t i) const noexcept {
502     ASMJIT_ASSERT(i < kFuncArgCountLoHi);
503     return _args[i].as<Operand>();
504   }
505 
506   //! Sets the function argument at `i` to `op`.
507   ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
508   //! Sets the function return value at `i` to `op`.
509   ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
510 
511   //! Sets the function argument at `i` to `reg`.
setArg(uint32_t i,const BaseReg & reg)512   inline bool setArg(uint32_t i, const BaseReg& reg) noexcept { return _setArg(i, reg); }
513   //! Sets the function argument at `i` to `imm`.
setArg(uint32_t i,const Imm & imm)514   inline bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
515 
516   //! Sets the function return value at `i` to `var`.
setRet(uint32_t i,const BaseReg & reg)517   inline bool setRet(uint32_t i, const BaseReg& reg) noexcept { return _setRet(i, reg); }
518 
519   //! \}
520 };
521 
522 // ============================================================================
523 // [asmjit::FuncPass]
524 // ============================================================================
525 
526 class ASMJIT_VIRTAPI FuncPass : public Pass {
527 public:
528   ASMJIT_NONCOPYABLE(FuncPass)
529   typedef Pass Base;
530 
531   //! \name Construction & Destruction
532   //! \{
533 
534   ASMJIT_API FuncPass(const char* name) noexcept;
535 
536   //! \}
537 
538   //! \name Accessors
539   //! \{
540 
541   //! Returns the associated `BaseCompiler`.
cc()542   inline BaseCompiler* cc() const noexcept { return static_cast<BaseCompiler*>(_cb); }
543 
544   //! \}
545 
546   //! \name Run
547   //! \{
548 
549   //! Calls `runOnFunction()` on each `FuncNode` node found.
550   ASMJIT_API Error run(Zone* zone, Logger* logger) noexcept override;
551 
552   //! Called once per `FuncNode`.
553   virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept = 0;
554 
555   //! \}
556 };
557 
558 //! \}
559 
560 ASMJIT_END_NAMESPACE
561 
562 #endif // !ASMJIT_NO_COMPILER
563 #endif // _ASMJIT_CORE_COMPILER_H
564