1 // [AsmJit]
2 // Complete JIT Assembler for C++ Language.
3 //
4 // [License]
5 // Zlib - See COPYING file in this package.
6 
7 // [Guard]
8 #ifndef _ASMJIT_X86_X86COMPILERCONTEXT_H
9 #define _ASMJIT_X86_X86COMPILERCONTEXT_H
10 
11 // [Dependencies - AsmJit]
12 #include "../core/intutil.h"
13 #include "../core/podvector.h"
14 
15 #include "../x86/x86assembler.h"
16 #include "../x86/x86compiler.h"
17 #include "../x86/x86compilerfunc.h"
18 #include "../x86/x86compileritem.h"
19 
20 // [Api-Begin]
21 #include "../core/apibegin.h"
22 
23 namespace AsmJit {
24 
25 //! @addtogroup AsmJit_X86
26 //! @{
27 
28 // ============================================================================
29 // [AsmJit::X86CompilerContext]
30 // ============================================================================
31 
32 //! @internal
33 //!
34 //! @brief Compiler context is used by @ref X86Compiler.
35 //!
36 //! X86Compiler context is used during compilation and normally developer doesn't
37 //! need access to it. The context is user per function (it's reset after each
38 //! function is generated).
39 struct X86CompilerContext : public CompilerContext
40 {
41   // --------------------------------------------------------------------------
42   // [Construction / Destruction]
43   // --------------------------------------------------------------------------
44 
45   //! @brief Create a new @ref X86CompilerContext instance.
46   ASMJIT_API X86CompilerContext(X86Compiler* x86Compiler);
47   //! @brief Destroy the @ref X86CompilerContext instance.
48   ASMJIT_API ~X86CompilerContext();
49 
50   // --------------------------------------------------------------------------
51   // [Accessor]
52   // --------------------------------------------------------------------------
53 
54   //! @brief Get compiler as @ref X86Compiler.
getCompilerX86CompilerContext55   inline X86Compiler* getCompiler() const
56   { return reinterpret_cast<X86Compiler*>(_compiler); }
57 
58   //! @brief Get function as @ref X86CompilerFuncDecl.
getFuncX86CompilerContext59   inline X86CompilerFuncDecl* getFunc() const
60   { return reinterpret_cast<X86CompilerFuncDecl*>(_func); }
61 
62   // --------------------------------------------------------------------------
63   // [Clear]
64   // --------------------------------------------------------------------------
65 
66   //! @brief Clear context, preparing it for next function generation.
67   ASMJIT_API void _clear();
68 
69   // --------------------------------------------------------------------------
70   // [Register Allocator]
71   // --------------------------------------------------------------------------
72 
73   //! @brief Allocate variable
74   //!
75   //! Calls @c allocGpVar, @c allocMmVar or @c allocXmmVar methods.
76   ASMJIT_API void allocVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags);
77 
78   //! @brief Save variable.
79   //!
80   //! Calls @c saveGpVar, @c saveMmVar or @c saveXmmVar methods.
81   ASMJIT_API void saveVar(X86CompilerVar* cv);
82 
83   //! @brief Spill variable.
84   //!
85   //! Calls @c spillGpVar, @c spillMmVar or @c spillXmmVar methods.
86   ASMJIT_API void spillVar(X86CompilerVar* cv);
87 
88   //! @brief Unuse variable (didn't spill, just forget about it).
89   ASMJIT_API void unuseVar(X86CompilerVar* cv, uint32_t toState);
90 
91   //! @brief Helper method that is called for each variable per item.
_unuseVarOnEndOfScopeX86CompilerContext92   inline void _unuseVarOnEndOfScope(CompilerItem* item, X86CompilerVar* cv)
93   {
94     if (cv->lastItem == item)
95       unuseVar(cv, kVarStateUnused);
96   }
97   //! @overload
_unuseVarOnEndOfScopeX86CompilerContext98   inline void _unuseVarOnEndOfScope(CompilerItem* item, VarAllocRecord* rec)
99   {
100     X86CompilerVar* cv = rec->vdata;
101     if (cv->lastItem == item || (rec->vflags & kVarAllocUnuseAfterUse))
102       unuseVar(cv, kVarStateUnused);
103   }
104   //! @overload
_unuseVarOnEndOfScopeX86CompilerContext105   inline void _unuseVarOnEndOfScope(CompilerItem* item, VarCallRecord* rec)
106   {
107     X86CompilerVar* v = rec->vdata;
108     if (v->lastItem == item || (rec->flags & VarCallRecord::kFlagUnuseAfterUse))
109       unuseVar(v, kVarStateUnused);
110   }
111 
112   //! @brief Allocate variable (GP).
113   ASMJIT_API void allocGpVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags);
114   //! @brief Save variable (GP).
115   ASMJIT_API void saveGpVar(X86CompilerVar* cv);
116   //! @brief Spill variable (GP).
117   ASMJIT_API void spillGpVar(X86CompilerVar* cv);
118 
119   //! @brief Allocate variable (MM).
120   ASMJIT_API void allocMmVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags);
121   //! @brief Save variable (MM).
122   ASMJIT_API void saveMmVar(X86CompilerVar* cv);
123   //! @brief Spill variable (MM).
124   ASMJIT_API void spillMmVar(X86CompilerVar* cv);
125 
126   //! @brief Allocate variable (XMM).
127   ASMJIT_API void allocXmmVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags);
128   //! @brief Save variable (XMM).
129   ASMJIT_API void saveXmmVar(X86CompilerVar* cv);
130   //! @brief Spill variable (XMM).
131   ASMJIT_API void spillXmmVar(X86CompilerVar* cv);
132 
133   //! @brief Emit load variable instruction(s).
134   ASMJIT_API void emitLoadVar(X86CompilerVar* cv, uint32_t regIndex);
135   //! @brief Emit save variable instruction(s).
136   ASMJIT_API void emitSaveVar(X86CompilerVar* cv, uint32_t regIndex);
137 
138   //! @brief Emit move variable instruction(s).
139   ASMJIT_API void emitMoveVar(X86CompilerVar* cv, uint32_t regIndex, uint32_t vflags);
140   //! @brief Emit exchange variable instruction(s).
141   ASMJIT_API void emitExchangeVar(X86CompilerVar* cv, uint32_t regIndex, uint32_t vflags, X86CompilerVar* other);
142 
143   //! @brief Called each time a variable is alloceted.
144   ASMJIT_API void _postAlloc(X86CompilerVar* cv, uint32_t vflags);
145   //! @brief Marks variable home memory as used (must be called at least once
146   //! for each variable that uses function local memory - stack).
147   ASMJIT_API void _markMemoryUsed(X86CompilerVar* cv);
148 
149   ASMJIT_API Mem _getVarMem(X86CompilerVar* cv);
150 
151   ASMJIT_API X86CompilerVar* _getSpillCandidateGP();
152   ASMJIT_API X86CompilerVar* _getSpillCandidateMM();
153   ASMJIT_API X86CompilerVar* _getSpillCandidateXMM();
154   ASMJIT_API X86CompilerVar* _getSpillCandidateGeneric(X86CompilerVar** varArray, uint32_t count);
155 
_isActiveX86CompilerContext156   inline bool _isActive(X86CompilerVar* cv)
157   { return cv->nextActive != NULL; }
158 
159   ASMJIT_API void _addActive(X86CompilerVar* cv);
160   ASMJIT_API void _freeActive(X86CompilerVar* cv);
161   ASMJIT_API void _freeAllActive();
162 
163   ASMJIT_API void _allocatedVariable(X86CompilerVar* cv);
164 
_allocatedGpRegisterX86CompilerContext165   inline void _allocatedGpRegister(uint32_t index)
166   {
167     _x86State.usedGP |= IntUtil::maskFromIndex(index);
168     _modifiedGpRegisters |= IntUtil::maskFromIndex(index);
169   }
170 
_allocatedMmRegisterX86CompilerContext171   inline void _allocatedMmRegister(uint32_t index)
172   {
173     _x86State.usedMM |= IntUtil::maskFromIndex(index);
174     _modifiedMmRegisters |= IntUtil::maskFromIndex(index);
175   }
176 
_allocatedXmmRegisterX86CompilerContext177   inline void _allocatedXmmRegister(uint32_t index)
178   {
179     _x86State.usedXMM |= IntUtil::maskFromIndex(index);
180     _modifiedXmmRegisters |= IntUtil::maskFromIndex(index);
181   }
182 
_freedGpRegisterX86CompilerContext183   inline void _freedGpRegister(uint32_t index)
184   { _x86State.usedGP &= ~IntUtil::maskFromIndex(index); }
185 
_freedMmRegisterX86CompilerContext186   inline void _freedMmRegister(uint32_t index)
187   { _x86State.usedMM &= ~IntUtil::maskFromIndex(index); }
188 
_freedXmmRegisterX86CompilerContext189   inline void _freedXmmRegister(uint32_t index)
190   { _x86State.usedXMM &= ~IntUtil::maskFromIndex(index); }
191 
_markGpRegisterModifiedX86CompilerContext192   inline void _markGpRegisterModified(uint32_t index)
193   { _modifiedGpRegisters |= IntUtil::maskFromIndex(index); }
194 
_markMmRegisterModifiedX86CompilerContext195   inline void _markMmRegisterModified(uint32_t index)
196   { _modifiedMmRegisters |= IntUtil::maskFromIndex(index); }
197 
_markXmmRegisterModifiedX86CompilerContext198   inline void _markXmmRegisterModified(uint32_t index)
199   { _modifiedXmmRegisters |= IntUtil::maskFromIndex(index); }
200 
201   // TODO: Find code which uses this and improve.
_newRegisterHomeIndexX86CompilerContext202   inline void _newRegisterHomeIndex(X86CompilerVar* cv, uint32_t idx)
203   {
204     if (cv->homeRegisterIndex == kRegIndexInvalid)
205       cv->homeRegisterIndex = idx;
206     cv->prefRegisterMask |= (1U << idx);
207   }
208 
209   // TODO: Find code which uses this and improve.
_newRegisterHomeMaskX86CompilerContext210   inline void _newRegisterHomeMask(X86CompilerVar* cv, uint32_t mask)
211   {
212     cv->prefRegisterMask |= mask;
213   }
214 
215   // --------------------------------------------------------------------------
216   // [Operand Patcher]
217   // --------------------------------------------------------------------------
218 
219   ASMJIT_API void translateOperands(Operand* operands, uint32_t count);
220 
221   // --------------------------------------------------------------------------
222   // [Backward Code]
223   // --------------------------------------------------------------------------
224 
225   ASMJIT_API void addBackwardCode(X86CompilerJmpInst* from);
226 
227   // --------------------------------------------------------------------------
228   // [Forward Jump]
229   // --------------------------------------------------------------------------
230 
231   ASMJIT_API void addForwardJump(X86CompilerJmpInst* inst);
232 
233   // --------------------------------------------------------------------------
234   // [State]
235   // --------------------------------------------------------------------------
236 
237   ASMJIT_API X86CompilerState* _saveState();
238   ASMJIT_API void _assignState(X86CompilerState* state);
239   ASMJIT_API void _restoreState(X86CompilerState* state, uint32_t targetOffset = kInvalidValue);
240 
241   // --------------------------------------------------------------------------
242   // [Memory Allocator]
243   // --------------------------------------------------------------------------
244 
245   ASMJIT_API VarMemBlock* _allocMemBlock(uint32_t size);
246   ASMJIT_API void _freeMemBlock(VarMemBlock* mem);
247 
248   ASMJIT_API void _allocMemoryOperands();
249   ASMJIT_API void _patchMemoryOperands(CompilerItem* start, CompilerItem* stop);
250 
251   // --------------------------------------------------------------------------
252   // [Members]
253   // --------------------------------------------------------------------------
254 
255   //! @brief X86 specific compiler state (linked with @ref _state).
256   X86CompilerState _x86State;
257 
258   //! @brief Forward jumps (single linked list).
259   ForwardJumpData* _forwardJumps;
260 
261   //! @brief Global modified GP registers mask (per function).
262   uint32_t _modifiedGpRegisters;
263   //! @brief Global modified MM registers mask (per function).
264   uint32_t _modifiedMmRegisters;
265   //! @brief Global modified XMM registers mask (per function).
266   uint32_t _modifiedXmmRegisters;
267 
268   //! @brief Whether the EBP/RBP register can be used by register allocator.
269   uint32_t _allocableEBP;
270 
271   //! @brief ESP adjust constant (changed during PUSH/POP or when using
272   //! stack.
273   int _adjustESP;
274 
275   //! @brief Function arguments base pointer (register).
276   uint32_t _argumentsBaseReg;
277   //! @brief Function arguments base offset.
278   int32_t _argumentsBaseOffset;
279   //! @brief Function arguments displacement.
280   int32_t _argumentsActualDisp;
281 
282   //! @brief Function variables base pointer (register).
283   uint32_t _variablesBaseReg;
284   //! @brief Function variables base offset.
285   int32_t _variablesBaseOffset;
286   //! @brief Function variables displacement.
287   int32_t _variablesActualDisp;
288 
289   //! @brief Used memory blocks (for variables, here is each created mem block
290   //! that can be also in _memFree list).
291   VarMemBlock* _memUsed;
292   //! @brief Free memory blocks (freed, prepared for another allocation).
293   VarMemBlock* _memFree;
294   //! @brief Count of 4-byte memory blocks used by the function.
295   uint32_t _mem4BlocksCount;
296   //! @brief Count of 8-byte memory blocks used by the function.
297   uint32_t _mem8BlocksCount;
298   //! @brief Count of 16-byte memory blocks used by the function.
299   uint32_t _mem16BlocksCount;
300   //! @brief Count of total bytes of stack memory used by the function.
301   uint32_t _memBytesTotal;
302 
303   //! @brief List of items which need to be translated. These items are filled
304   //! by @c addBackwardCode().
305   PodVector<X86CompilerJmpInst*> _backCode;
306 
307   //! @brief Backward code position (starts at 0).
308   sysuint_t _backPos;
309   //! @brief Whether to emit comments.
310   bool _emitComments;
311 };
312 
313 //! @}
314 
315 } // AsmJit namespace
316 
317 // [Api-End]
318 #include "../core/apiend.h"
319 
320 // [Guard]
321 #endif // _ASMJIT_X86_X86COMPILERCONTEXT_H
322