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 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Guard]
33 : #include "./asmjit_build.h"
34 : #if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_DISABLE_COMPILER)
35 :
36 : // [Dependencies]
37 : #include "./cpuinfo.h"
38 : #include "./utils.h"
39 : #include "./x86assembler.h"
40 : #include "./x86compiler.h"
41 : #include "./x86internal_p.h"
42 : #include "./x86regalloc_p.h"
43 :
44 : // [Api-Begin]
45 : #include "./asmjit_apibegin.h"
46 :
47 : namespace PLMD {
48 : namespace asmjit {
49 :
50 : // ============================================================================
51 : // [Forward Declarations]
52 : // ============================================================================
53 :
54 : enum { kCompilerDefaultLookAhead = 64 };
55 :
56 : static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount);
57 :
58 : // ============================================================================
59 : // [asmjit::X86RAPass - SpecialInst]
60 : // ============================================================================
61 :
62 : struct X86SpecialInst {
63 : uint8_t inReg;
64 : uint8_t outReg;
65 : uint16_t flags;
66 : };
67 :
68 : static ASMJIT_INLINE const X86SpecialInst* X86SpecialInst_get(uint32_t instId, const Operand* opArray, uint32_t opCount) noexcept {
69 : enum { kAny = Globals::kInvalidRegId };
70 :
71 : #define R(ri) { uint8_t(ri) , uint8_t(kAny), uint16_t(TiedReg::kRReg) }
72 : #define W(ri) { uint8_t(kAny), uint8_t(ri) , uint16_t(TiedReg::kWReg) }
73 : #define X(ri) { uint8_t(ri) , uint8_t(ri) , uint16_t(TiedReg::kXReg) }
74 : #define NONE() { uint8_t(kAny), uint8_t(kAny), 0 }
75 : static const X86SpecialInst instCpuid[] = { X(X86Gp::kIdAx), W(X86Gp::kIdBx), X(X86Gp::kIdCx), W(X86Gp::kIdDx) };
76 : static const X86SpecialInst instCbwCdqeCwde[] = { X(X86Gp::kIdAx) };
77 : static const X86SpecialInst instCdqCwdCqo[] = { W(X86Gp::kIdDx), R(X86Gp::kIdAx) };
78 : static const X86SpecialInst instCmpxchg[] = { X(kAny), R(kAny), X(X86Gp::kIdAx) };
79 : static const X86SpecialInst instCmpxchg8b16b[] = { NONE(), X(X86Gp::kIdDx), X(X86Gp::kIdAx), R(X86Gp::kIdCx), R(X86Gp::kIdBx) };
80 : static const X86SpecialInst instDaaDas[] = { X(X86Gp::kIdAx) };
81 : static const X86SpecialInst instDiv2[] = { X(X86Gp::kIdAx), R(kAny) };
82 : static const X86SpecialInst instDiv3[] = { X(X86Gp::kIdDx), X(X86Gp::kIdAx), R(kAny) };
83 : static const X86SpecialInst instJecxz[] = { R(X86Gp::kIdCx) };
84 : static const X86SpecialInst instMul2[] = { X(X86Gp::kIdAx), R(kAny) };
85 : static const X86SpecialInst instMul3[] = { W(X86Gp::kIdDx), X(X86Gp::kIdAx), R(kAny) };
86 : static const X86SpecialInst instMulx[] = { W(kAny), W(kAny), R(kAny), R(X86Gp::kIdDx) };
87 : static const X86SpecialInst instLahf[] = { W(X86Gp::kIdAx) };
88 : static const X86SpecialInst instSahf[] = { R(X86Gp::kIdAx) };
89 : static const X86SpecialInst instMaskmovq[] = { R(kAny), R(kAny), R(X86Gp::kIdDi) };
90 : static const X86SpecialInst instRdtscRdtscp[] = { W(X86Gp::kIdDx), W(X86Gp::kIdAx), W(X86Gp::kIdCx) };
91 : static const X86SpecialInst instRot[] = { X(kAny), R(X86Gp::kIdCx) };
92 : static const X86SpecialInst instShldShrd[] = { X(kAny), R(kAny), R(X86Gp::kIdCx) };
93 : static const X86SpecialInst instThirdXMM0[] = { W(kAny), R(kAny), R(0) };
94 : static const X86SpecialInst instPcmpestri[] = { R(kAny), R(kAny), NONE(), W(X86Gp::kIdCx) };
95 : static const X86SpecialInst instPcmpestrm[] = { R(kAny), R(kAny), NONE(), W(0) };
96 : static const X86SpecialInst instPcmpistri[] = { R(kAny), R(kAny), NONE(), W(X86Gp::kIdCx), R(X86Gp::kIdAx), R(X86Gp::kIdDx) };
97 : static const X86SpecialInst instPcmpistrm[] = { R(kAny), R(kAny), NONE(), W(0) , R(X86Gp::kIdAx), R(X86Gp::kIdDx) };
98 : static const X86SpecialInst instXsaveXrstor[] = { W(kAny), R(X86Gp::kIdDx), R(X86Gp::kIdAx) };
99 : static const X86SpecialInst instReadMR[] = { W(X86Gp::kIdDx), W(X86Gp::kIdAx), R(X86Gp::kIdCx) };
100 : static const X86SpecialInst instWriteMR[] = { R(X86Gp::kIdDx), R(X86Gp::kIdAx), R(X86Gp::kIdCx) };
101 :
102 : static const X86SpecialInst instCmps[] = { X(X86Gp::kIdSi), X(X86Gp::kIdDi) };
103 : static const X86SpecialInst instLods[] = { W(X86Gp::kIdAx), X(X86Gp::kIdSi) };
104 : static const X86SpecialInst instMovs[] = { X(X86Gp::kIdDi), X(X86Gp::kIdSi) };
105 : static const X86SpecialInst instScas[] = { X(X86Gp::kIdDi), R(X86Gp::kIdAx) };
106 : static const X86SpecialInst instStos[] = { X(X86Gp::kIdDi), R(X86Gp::kIdAx) };
107 : #undef NONE
108 : #undef X
109 : #undef W
110 : #undef R
111 :
112 0 : switch (instId) {
113 : case X86Inst::kIdCpuid : return instCpuid;
114 0 : case X86Inst::kIdCbw :
115 : case X86Inst::kIdCdqe :
116 0 : case X86Inst::kIdCwde : return instCbwCdqeCwde;
117 0 : case X86Inst::kIdCdq :
118 : case X86Inst::kIdCwd :
119 0 : case X86Inst::kIdCqo : return instCdqCwdCqo;
120 0 : case X86Inst::kIdCmps : return instCmps;
121 0 : case X86Inst::kIdCmpxchg : return instCmpxchg;
122 0 : case X86Inst::kIdCmpxchg8b :
123 0 : case X86Inst::kIdCmpxchg16b : return instCmpxchg8b16b;
124 0 : case X86Inst::kIdDaa :
125 0 : case X86Inst::kIdDas : return instDaaDas;
126 0 : case X86Inst::kIdDiv : return (opCount == 2) ? instDiv2 : instDiv3;
127 0 : case X86Inst::kIdIdiv : return (opCount == 2) ? instDiv2 : instDiv3;
128 0 : case X86Inst::kIdImul : if (opCount == 2) return nullptr;
129 0 : if (opCount == 3 && !(opArray[0].isReg() && opArray[1].isReg() && opArray[2].isRegOrMem())) return nullptr;
130 : ASMJIT_FALLTHROUGH;
131 0 : case X86Inst::kIdMul : return (opCount == 2) ? instMul2 : instMul3;
132 0 : case X86Inst::kIdMulx : return instMulx;
133 0 : case X86Inst::kIdJecxz : return instJecxz;
134 0 : case X86Inst::kIdLods : return instLods;
135 0 : case X86Inst::kIdMovs : return instMovs;
136 0 : case X86Inst::kIdLahf : return instLahf;
137 0 : case X86Inst::kIdSahf : return instSahf;
138 0 : case X86Inst::kIdMaskmovq :
139 : case X86Inst::kIdMaskmovdqu :
140 0 : case X86Inst::kIdVmaskmovdqu: return instMaskmovq;
141 : case X86Inst::kIdEnter : return nullptr; // Not supported.
142 : case X86Inst::kIdLeave : return nullptr; // Not supported.
143 : case X86Inst::kIdRet : return nullptr; // Not supported.
144 : case X86Inst::kIdMonitor : return nullptr; // TODO: [COMPILER] Monitor/MWait.
145 : case X86Inst::kIdMwait : return nullptr; // TODO: [COMPILER] Monitor/MWait.
146 : case X86Inst::kIdPop : return nullptr; // TODO: [COMPILER] Pop/Push.
147 : case X86Inst::kIdPush : return nullptr; // TODO: [COMPILER] Pop/Push.
148 : case X86Inst::kIdPopa : return nullptr; // Not supported.
149 : case X86Inst::kIdPopf : return nullptr; // Not supported.
150 : case X86Inst::kIdPusha : return nullptr; // Not supported.
151 : case X86Inst::kIdPushf : return nullptr; // Not supported.
152 0 : case X86Inst::kIdRcl :
153 : case X86Inst::kIdRcr :
154 : case X86Inst::kIdRol :
155 : case X86Inst::kIdRor :
156 : case X86Inst::kIdSal :
157 : case X86Inst::kIdSar :
158 : case X86Inst::kIdShl : // Rot instruction is special only if the last operand is a variable.
159 0 : case X86Inst::kIdShr : if (!opArray[1].isReg()) return nullptr;
160 : return instRot;
161 0 : case X86Inst::kIdShld : // Shld/Shrd instruction is special only if the last operand is a variable.
162 0 : case X86Inst::kIdShrd : if (!opArray[2].isReg()) return nullptr;
163 : return instShldShrd;
164 0 : case X86Inst::kIdRdtsc :
165 0 : case X86Inst::kIdRdtscp : return instRdtscRdtscp;
166 0 : case X86Inst::kIdScas : return instScas;
167 0 : case X86Inst::kIdStos : return instStos;
168 0 : case X86Inst::kIdBlendvpd :
169 : case X86Inst::kIdBlendvps :
170 : case X86Inst::kIdPblendvb :
171 0 : case X86Inst::kIdSha256rnds2: return instThirdXMM0;
172 0 : case X86Inst::kIdPcmpestri :
173 0 : case X86Inst::kIdVpcmpestri : return instPcmpestri;
174 0 : case X86Inst::kIdPcmpistri :
175 0 : case X86Inst::kIdVpcmpistri : return instPcmpistri;
176 0 : case X86Inst::kIdPcmpestrm :
177 0 : case X86Inst::kIdVpcmpestrm : return instPcmpestrm;
178 0 : case X86Inst::kIdPcmpistrm :
179 0 : case X86Inst::kIdVpcmpistrm : return instPcmpistrm;
180 0 : case X86Inst::kIdXrstor :
181 : case X86Inst::kIdXrstor64 :
182 : case X86Inst::kIdXsave :
183 : case X86Inst::kIdXsave64 :
184 : case X86Inst::kIdXsaveopt :
185 0 : case X86Inst::kIdXsaveopt64 : return instXsaveXrstor;
186 0 : case X86Inst::kIdRdmsr :
187 : case X86Inst::kIdRdpmc :
188 0 : case X86Inst::kIdXgetbv : return instReadMR;
189 0 : case X86Inst::kIdWrmsr :
190 0 : case X86Inst::kIdXsetbv : return instWriteMR;
191 : default : return nullptr;
192 : }
193 : }
194 :
195 : // ============================================================================
196 : // [asmjit::X86RAPass - Construction / Destruction]
197 : // ============================================================================
198 :
199 1944 : X86RAPass::X86RAPass() noexcept : RAPass() {
200 1944 : _state = &_x86State;
201 1944 : _varMapToVaListOffset = ASMJIT_OFFSET_OF(X86RAData, tiedArray);
202 1944 : }
203 0 : X86RAPass::~X86RAPass() noexcept {}
204 :
205 : // ============================================================================
206 : // [asmjit::X86RAPass - Interface]
207 : // ============================================================================
208 :
209 1944 : Error X86RAPass::process(Zone* zone) noexcept {
210 1944 : return Base::process(zone);
211 : }
212 :
213 1944 : Error X86RAPass::prepare(CCFunc* func) noexcept {
214 1944 : ASMJIT_PROPAGATE(Base::prepare(func));
215 :
216 : uint32_t archType = cc()->getArchType();
217 1944 : _regCount._gp = archType == ArchInfo::kTypeX86 ? 8 : 16;
218 1944 : _regCount._mm = 8;
219 1944 : _regCount._k = 8;
220 1944 : _regCount._vec = archType == ArchInfo::kTypeX86 ? 8 : 16;
221 : _zsp = cc()->zsp();
222 : _zbp = cc()->zbp();
223 :
224 1944 : _gaRegs[X86Reg::kKindGp ] = Utils::bits(_regCount.getGp()) & ~Utils::mask(X86Gp::kIdSp);
225 1944 : _gaRegs[X86Reg::kKindMm ] = Utils::bits(_regCount.getMm());
226 1944 : _gaRegs[X86Reg::kKindK ] = Utils::bits(_regCount.getK());
227 1944 : _gaRegs[X86Reg::kKindVec] = Utils::bits(_regCount.getVec());
228 :
229 1944 : _x86State.reset(0);
230 : _clobberedRegs.reset();
231 :
232 1944 : _avxEnabled = false;
233 :
234 1944 : _varBaseRegId = Globals::kInvalidRegId; // Used by patcher.
235 1944 : _varBaseOffset = 0; // Used by patcher.
236 :
237 1944 : return kErrorOk;
238 : }
239 :
240 : // ============================================================================
241 : // [asmjit::X86RAPass - Emit]
242 : // ============================================================================
243 :
244 656 : Error X86RAPass::emitMove(VirtReg* vReg, uint32_t dstId, uint32_t srcId, const char* reason) {
245 : const char* comment = nullptr;
246 656 : if (_emitComments) {
247 0 : _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
248 : comment = _stringBuilder.getData();
249 : }
250 :
251 : X86Reg dst(X86Reg::fromSignature(vReg->getSignature(), dstId));
252 : X86Reg src(X86Reg::fromSignature(vReg->getSignature(), srcId));
253 656 : return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
254 : }
255 :
256 4424 : Error X86RAPass::emitLoad(VirtReg* vReg, uint32_t id, const char* reason) {
257 : const char* comment = nullptr;
258 4424 : if (_emitComments) {
259 0 : _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
260 : comment = _stringBuilder.getData();
261 : }
262 :
263 : X86Reg dst(X86Reg::fromSignature(vReg->getSignature(), id));
264 : X86Mem src(getVarMem(vReg));
265 4424 : return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
266 : }
267 :
268 4004 : Error X86RAPass::emitSave(VirtReg* vReg, uint32_t id, const char* reason) {
269 : const char* comment = nullptr;
270 4004 : if (_emitComments) {
271 0 : _stringBuilder.setFormat("[%s] %s", reason, vReg->getName());
272 : comment = _stringBuilder.getData();
273 : }
274 :
275 : X86Mem dst(getVarMem(vReg));
276 : X86Reg src(X86Reg::fromSignature(vReg->getSignature(), id));
277 4004 : return X86Internal::emitRegMove(reinterpret_cast<X86Emitter*>(cc()), dst, src, vReg->getTypeId(), _avxEnabled, comment);
278 : }
279 :
280 0 : Error X86RAPass::emitSwapGp(VirtReg* dstReg, VirtReg* srcReg, uint32_t dstPhysId, uint32_t srcPhysId, const char* reason) noexcept {
281 : ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
282 : ASMJIT_ASSERT(srcPhysId != Globals::kInvalidRegId);
283 :
284 0 : uint32_t is64 = std::max(dstReg->getTypeId(), srcReg->getTypeId()) >= TypeId::kI64;
285 0 : uint32_t sign = is64 ? uint32_t(X86RegTraits<X86Reg::kRegGpq>::kSignature)
286 : : uint32_t(X86RegTraits<X86Reg::kRegGpd>::kSignature);
287 :
288 : X86Reg a = X86Reg::fromSignature(sign, dstPhysId);
289 : X86Reg b = X86Reg::fromSignature(sign, srcPhysId);
290 :
291 0 : ASMJIT_PROPAGATE(cc()->emit(X86Inst::kIdXchg, a, b));
292 0 : if (_emitComments)
293 0 : cc()->getCursor()->setInlineComment(cc()->_cbDataZone.sformat("[%s] %s, %s", reason, dstReg->getName(), srcReg->getName()));
294 : return kErrorOk;
295 : }
296 :
297 404 : Error X86RAPass::emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept {
298 : ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
299 :
300 : X86Reg r0;
301 : Imm imm(*src);
302 :
303 404 : switch (dstTypeId) {
304 : case TypeId::kI8:
305 : case TypeId::kU8:
306 : imm.truncateTo8Bits();
307 : ASMJIT_FALLTHROUGH;
308 :
309 0 : case TypeId::kI16:
310 : case TypeId::kU16:
311 : imm.truncateTo16Bits();
312 : ASMJIT_FALLTHROUGH;
313 :
314 : case TypeId::kI32:
315 : case TypeId::kU32:
316 0 : Mov32Truncate:
317 : imm.truncateTo32Bits();
318 : r0.setX86RegT<X86Reg::kRegGpd>(dstPhysId);
319 0 : cc()->emit(X86Inst::kIdMov, r0, imm);
320 0 : break;
321 :
322 : case TypeId::kI64:
323 : case TypeId::kU64:
324 : // Move to GPD register will also clear the high DWORD of GPQ
325 : // register in 64-bit mode.
326 404 : if (imm.isUInt32())
327 0 : goto Mov32Truncate;
328 :
329 : r0.setX86RegT<X86Reg::kRegGpq>(dstPhysId);
330 404 : cc()->emit(X86Inst::kIdMov, r0, imm);
331 404 : break;
332 :
333 : case TypeId::kF32:
334 : case TypeId::kF64:
335 : // Compiler doesn't manage FPU stack.
336 : ASMJIT_NOT_REACHED();
337 : break;
338 :
339 : case TypeId::kMmx32:
340 : case TypeId::kMmx64:
341 : // TODO: [COMPILER] EmitMoveImmToReg.
342 : break;
343 :
344 : default:
345 : // TODO: [COMPILER] EmitMoveImmToReg.
346 : break;
347 : }
348 :
349 404 : return kErrorOk;
350 : }
351 :
352 0 : Error X86RAPass::emitImmToStack(uint32_t dstTypeId, const X86Mem* dst, const Imm* src) noexcept {
353 : X86Mem mem(*dst);
354 : Imm imm(*src);
355 :
356 : // One stack entry has the same size as the native register size. That means
357 : // that if we want to move a 32-bit integer on the stack in 64-bit mode, we
358 : // need to extend it to a 64-bit integer first. In 32-bit mode, pushing a
359 : // 64-bit on stack is done in two steps by pushing low and high parts
360 : // separately.
361 : uint32_t gpSize = cc()->getGpSize();
362 :
363 0 : switch (dstTypeId) {
364 : case TypeId::kI8:
365 : case TypeId::kU8:
366 : imm.truncateTo8Bits();
367 : ASMJIT_FALLTHROUGH;
368 :
369 0 : case TypeId::kI16:
370 : case TypeId::kU16:
371 : imm.truncateTo16Bits();
372 : ASMJIT_FALLTHROUGH;
373 :
374 0 : case TypeId::kI32:
375 : case TypeId::kU32:
376 : case TypeId::kF32:
377 : mem.setSize(4);
378 : imm.truncateTo32Bits();
379 0 : cc()->emit(X86Inst::kIdMov, mem, imm);
380 0 : break;
381 :
382 0 : case TypeId::kI64:
383 : case TypeId::kU64:
384 : case TypeId::kF64:
385 : case TypeId::kMmx32:
386 : case TypeId::kMmx64:
387 0 : if (gpSize == 4) {
388 : uint32_t hi = imm.getUInt32Hi();
389 :
390 : // Lo-Part.
391 : mem.setSize(4);
392 : imm.truncateTo32Bits();
393 :
394 0 : cc()->emit(X86Inst::kIdMov, mem, imm);
395 : mem.addOffsetLo32(gpSize);
396 :
397 : // Hi-Part.
398 : imm.setUInt32(hi);
399 0 : cc()->emit(X86Inst::kIdMov, mem, imm);
400 : }
401 : else {
402 : mem.setSize(8);
403 0 : cc()->emit(X86Inst::kIdMov, mem, imm);
404 : }
405 : break;
406 :
407 : default:
408 : return DebugUtils::errored(kErrorInvalidState);
409 : }
410 :
411 : return kErrorOk;
412 : }
413 :
414 0 : Error X86RAPass::emitRegToStack(uint32_t dstTypeId, const X86Mem* dst, uint32_t srcTypeId, uint32_t srcPhysId) noexcept {
415 : ASMJIT_ASSERT(srcPhysId != Globals::kInvalidRegId);
416 :
417 : X86Mem m0(*dst);
418 : X86Reg r0, r1;
419 :
420 : uint32_t gpSize = cc()->getGpSize();
421 : uint32_t instId = 0;
422 :
423 0 : switch (dstTypeId) {
424 : case TypeId::kI64:
425 : case TypeId::kU64:
426 : // Extend BYTE->QWORD (GP).
427 0 : if (TypeId::isGpb(srcTypeId)) {
428 : r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
429 :
430 0 : instId = (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI8) ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
431 0 : goto _ExtendMovGpXQ;
432 : }
433 :
434 : // Extend WORD->QWORD (GP).
435 : if (TypeId::isGpw(srcTypeId)) {
436 : r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
437 :
438 0 : instId = (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI16) ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
439 0 : goto _ExtendMovGpXQ;
440 : }
441 :
442 : // Extend DWORD->QWORD (GP).
443 : if (TypeId::isGpd(srcTypeId)) {
444 : r1.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
445 :
446 : instId = X86Inst::kIdMovsxd;
447 0 : if (dstTypeId == TypeId::kI64 && srcTypeId == TypeId::kI32)
448 0 : goto _ExtendMovGpXQ;
449 : else
450 0 : goto _ZeroExtendGpDQ;
451 : }
452 :
453 : // Move QWORD (GP).
454 0 : if (TypeId::isGpq(srcTypeId)) goto MovGpQ;
455 0 : if (TypeId::isMmx(srcTypeId)) goto MovMmQ;
456 0 : if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
457 : break;
458 :
459 : case TypeId::kI32:
460 : case TypeId::kU32:
461 : case TypeId::kI16:
462 : case TypeId::kU16:
463 : // DWORD <- WORD (Zero|Sign Extend).
464 0 : if (TypeId::isGpw(srcTypeId)) {
465 0 : bool isDstSigned = dstTypeId == TypeId::kI16 || dstTypeId == TypeId::kI32;
466 0 : bool isSrcSigned = srcTypeId == TypeId::kI8 || srcTypeId == TypeId::kI16;
467 :
468 : r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
469 0 : instId = isDstSigned && isSrcSigned ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
470 0 : goto _ExtendMovGpD;
471 : }
472 :
473 : // DWORD <- BYTE (Zero|Sign Extend).
474 0 : if (TypeId::isGpb(srcTypeId)) {
475 0 : bool isDstSigned = dstTypeId == TypeId::kI16 || dstTypeId == TypeId::kI32;
476 0 : bool isSrcSigned = srcTypeId == TypeId::kI8 || srcTypeId == TypeId::kI16;
477 :
478 : r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
479 0 : instId = isDstSigned && isSrcSigned ? X86Inst::kIdMovsx : X86Inst::kIdMovzx;
480 0 : goto _ExtendMovGpD;
481 : }
482 : ASMJIT_FALLTHROUGH;
483 :
484 : case TypeId::kI8:
485 : case TypeId::kU8:
486 0 : if (TypeId::isInt(srcTypeId)) goto MovGpD;
487 0 : if (TypeId::isMmx(srcTypeId)) goto MovMmD;
488 0 : if (TypeId::isVec(srcTypeId)) goto MovXmmD;
489 : break;
490 :
491 : case TypeId::kMmx32:
492 : case TypeId::kMmx64:
493 : // Extend BYTE->QWORD (GP).
494 0 : if (TypeId::isGpb(srcTypeId)) {
495 : r1.setX86RegT<X86Reg::kRegGpbLo>(srcPhysId);
496 :
497 : instId = X86Inst::kIdMovzx;
498 0 : goto _ExtendMovGpXQ;
499 : }
500 :
501 : // Extend WORD->QWORD (GP).
502 : if (TypeId::isGpw(srcTypeId)) {
503 : r1.setX86RegT<X86Reg::kRegGpw>(srcPhysId);
504 :
505 : instId = X86Inst::kIdMovzx;
506 0 : goto _ExtendMovGpXQ;
507 : }
508 :
509 0 : if (TypeId::isGpd(srcTypeId)) goto _ExtendMovGpDQ;
510 0 : if (TypeId::isGpq(srcTypeId)) goto MovGpQ;
511 0 : if (TypeId::isMmx(srcTypeId)) goto MovMmQ;
512 0 : if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
513 : break;
514 :
515 : case TypeId::kF32:
516 : case TypeId::kF32x1:
517 0 : if (TypeId::isVec(srcTypeId)) goto MovXmmD;
518 : break;
519 :
520 : case TypeId::kF64:
521 : case TypeId::kF64x1:
522 0 : if (TypeId::isVec(srcTypeId)) goto MovXmmQ;
523 : break;
524 :
525 : default:
526 : // TODO: Vector types by stack.
527 : break;
528 : }
529 : return DebugUtils::errored(kErrorInvalidState);
530 :
531 : // Extend+Move Gp.
532 0 : _ExtendMovGpD:
533 : m0.setSize(4);
534 : r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
535 :
536 0 : cc()->emit(instId, r0, r1);
537 0 : cc()->emit(X86Inst::kIdMov, m0, r0);
538 0 : return kErrorOk;
539 :
540 0 : _ExtendMovGpXQ:
541 0 : if (gpSize == 8) {
542 : m0.setSize(8);
543 : r0.setX86RegT<X86Reg::kRegGpq>(srcPhysId);
544 :
545 0 : cc()->emit(instId, r0, r1);
546 0 : cc()->emit(X86Inst::kIdMov, m0, r0);
547 : }
548 : else {
549 : m0.setSize(4);
550 : r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
551 :
552 0 : cc()->emit(instId, r0, r1);
553 :
554 0 : _ExtendMovGpDQ:
555 0 : cc()->emit(X86Inst::kIdMov, m0, r0);
556 : m0.addOffsetLo32(4);
557 0 : cc()->emit(X86Inst::kIdAnd, m0, 0);
558 : }
559 : return kErrorOk;
560 :
561 : _ZeroExtendGpDQ:
562 : m0.setSize(4);
563 : r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
564 0 : goto _ExtendMovGpDQ;
565 :
566 : // Move Gp.
567 : MovGpD:
568 : m0.setSize(4);
569 : r0.setX86RegT<X86Reg::kRegGpd>(srcPhysId);
570 0 : return cc()->emit(X86Inst::kIdMov, m0, r0);
571 :
572 0 : MovGpQ:
573 : m0.setSize(8);
574 : r0.setX86RegT<X86Reg::kRegGpq>(srcPhysId);
575 0 : return cc()->emit(X86Inst::kIdMov, m0, r0);
576 :
577 : // Move Mm.
578 : MovMmD:
579 : m0.setSize(4);
580 : r0.setX86RegT<X86Reg::kRegMm>(srcPhysId);
581 0 : return cc()->emit(X86Inst::kIdMovd, m0, r0);
582 :
583 0 : MovMmQ:
584 : m0.setSize(8);
585 : r0.setX86RegT<X86Reg::kRegMm>(srcPhysId);
586 0 : return cc()->emit(X86Inst::kIdMovq, m0, r0);
587 :
588 : // Move XMM.
589 0 : MovXmmD:
590 : m0.setSize(4);
591 : r0.setX86RegT<X86Reg::kRegXmm>(srcPhysId);
592 0 : return cc()->emit(X86Inst::kIdMovss, m0, r0);
593 :
594 0 : MovXmmQ:
595 : m0.setSize(8);
596 : r0.setX86RegT<X86Reg::kRegXmm>(srcPhysId);
597 0 : return cc()->emit(X86Inst::kIdMovlps, m0, r0);
598 : }
599 :
600 : // ============================================================================
601 : // [asmjit::X86RAPass - Register Management]
602 : // ============================================================================
603 :
604 : #if defined(ASMJIT_DEBUG)
605 : template<int C>
606 : static ASMJIT_INLINE void X86RAPass_checkStateVars(X86RAPass* self) {
607 : X86RAState* state = self->getState();
608 : VirtReg** sVars = state->getListByKind(C);
609 :
610 : uint32_t physId;
611 : uint32_t regMask;
612 : uint32_t regCount = self->_regCount.get(C);
613 :
614 : uint32_t occupied = state->_occupied.get(C);
615 : uint32_t modified = state->_modified.get(C);
616 :
617 : for (physId = 0, regMask = 1; physId < regCount; physId++, regMask <<= 1) {
618 : VirtReg* vreg = sVars[physId];
619 :
620 : if (!vreg) {
621 : ASMJIT_ASSERT((occupied & regMask) == 0);
622 : ASMJIT_ASSERT((modified & regMask) == 0);
623 : }
624 : else {
625 : ASMJIT_ASSERT((occupied & regMask) != 0);
626 : ASMJIT_ASSERT((modified & regMask) == (static_cast<uint32_t>(vreg->isModified()) << physId));
627 :
628 : ASMJIT_ASSERT(vreg->getKind() == C);
629 : ASMJIT_ASSERT(vreg->getState() == VirtReg::kStateReg);
630 : ASMJIT_ASSERT(vreg->getPhysId() == physId);
631 : }
632 : }
633 : }
634 :
635 : void X86RAPass::_checkState() {
636 : X86RAPass_checkStateVars<X86Reg::kKindGp >(this);
637 : X86RAPass_checkStateVars<X86Reg::kKindMm >(this);
638 : X86RAPass_checkStateVars<X86Reg::kKindVec>(this);
639 : }
640 : #else
641 0 : void X86RAPass::_checkState() {}
642 : #endif // ASMJIT_DEBUG
643 :
644 : // ============================================================================
645 : // [asmjit::X86RAPass - State - Load]
646 : // ============================================================================
647 :
648 : template<int C>
649 : static ASMJIT_INLINE void X86RAPass_loadStateVars(X86RAPass* self, X86RAState* src) {
650 : X86RAState* cur = self->getState();
651 :
652 : VirtReg** cVars = cur->getListByKind(C);
653 : VirtReg** sVars = src->getListByKind(C);
654 :
655 : uint32_t physId;
656 : uint32_t modified = src->_modified.get(C);
657 : uint32_t regCount = self->_regCount.get(C);
658 :
659 0 : for (physId = 0; physId < regCount; physId++, modified >>= 1) {
660 0 : VirtReg* vreg = sVars[physId];
661 0 : cVars[physId] = vreg;
662 0 : if (!vreg) continue;
663 :
664 : vreg->setState(VirtReg::kStateReg);
665 : vreg->setPhysId(physId);
666 0 : vreg->setModified(modified & 0x1);
667 : }
668 : }
669 :
670 0 : void X86RAPass::loadState(RAState* src_) {
671 : X86RAState* cur = getState();
672 : X86RAState* src = static_cast<X86RAState*>(src_);
673 :
674 : VirtReg** vregs = _contextVd.getData();
675 0 : uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
676 :
677 : // Load allocated variables.
678 : X86RAPass_loadStateVars<X86Reg::kKindGp >(this, src);
679 : X86RAPass_loadStateVars<X86Reg::kKindMm >(this, src);
680 : X86RAPass_loadStateVars<X86Reg::kKindVec>(this, src);
681 :
682 : // Load masks.
683 0 : cur->_occupied = src->_occupied;
684 0 : cur->_modified = src->_modified;
685 :
686 : // Load states of other variables and clear their 'Modified' flags.
687 0 : for (uint32_t i = 0; i < count; i++) {
688 : uint32_t vState = src->_cells[i].getState();
689 :
690 0 : if (vState == VirtReg::kStateReg)
691 0 : continue;
692 :
693 0 : vregs[i]->setState(vState);
694 0 : vregs[i]->setPhysId(Globals::kInvalidRegId);
695 0 : vregs[i]->setModified(false);
696 : }
697 :
698 : ASMJIT_X86_CHECK_STATE
699 0 : }
700 :
701 : // ============================================================================
702 : // [asmjit::X86RAPass - State - Save]
703 : // ============================================================================
704 :
705 0 : RAState* X86RAPass::saveState() {
706 : VirtReg** vregs = _contextVd.getData();
707 0 : uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
708 :
709 : size_t size = Utils::alignTo<size_t>(
710 : sizeof(X86RAState) + count * sizeof(X86StateCell), sizeof(void*));
711 :
712 : X86RAState* cur = getState();
713 0 : X86RAState* dst = _zone->allocT<X86RAState>(size);
714 0 : if (!dst) return nullptr;
715 :
716 : // Store links.
717 0 : ::memcpy(dst->_list, cur->_list, X86RAState::kAllCount * sizeof(VirtReg*));
718 :
719 : // Store masks.
720 0 : dst->_occupied = cur->_occupied;
721 0 : dst->_modified = cur->_modified;
722 :
723 : // Store cells.
724 0 : for (uint32_t i = 0; i < count; i++) {
725 0 : VirtReg* vreg = static_cast<VirtReg*>(vregs[i]);
726 : X86StateCell& cell = dst->_cells[i];
727 :
728 : cell.reset();
729 : cell.setState(vreg->getState());
730 : }
731 :
732 : return dst;
733 : }
734 :
735 : // ============================================================================
736 : // [asmjit::X86RAPass - State - Switch]
737 : // ============================================================================
738 :
739 : template<int C>
740 : static ASMJIT_INLINE void X86RAPass_switchStateVars(X86RAPass* self, X86RAState* src) {
741 : X86RAState* dst = self->getState();
742 :
743 : VirtReg** dVars = dst->getListByKind(C);
744 : VirtReg** sVars = src->getListByKind(C);
745 :
746 0 : X86StateCell* cells = src->_cells;
747 : uint32_t regCount = self->_regCount.get(C);
748 : bool didWork;
749 :
750 0 : do {
751 : didWork = false;
752 :
753 0 : for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
754 0 : VirtReg* dVReg = dVars[physId];
755 0 : VirtReg* sVd = sVars[physId];
756 0 : if (dVReg == sVd) continue;
757 :
758 0 : if (dVReg) {
759 0 : const X86StateCell& cell = cells[dVReg->_raId];
760 :
761 0 : if (cell.getState() != VirtReg::kStateReg) {
762 0 : if (cell.getState() == VirtReg::kStateMem)
763 : self->spill<C>(dVReg);
764 : else
765 : self->unuse<C>(dVReg);
766 :
767 : dVReg = nullptr;
768 : didWork = true;
769 0 : if (!sVd) continue;
770 : }
771 : }
772 :
773 0 : if (!dVReg && sVd) {
774 0 : _MoveOrLoad:
775 0 : if (sVd->getPhysId() != Globals::kInvalidRegId)
776 : self->move<C>(sVd, physId);
777 : else
778 : self->load<C>(sVd, physId);
779 :
780 : didWork = true;
781 0 : continue;
782 : }
783 :
784 0 : if (dVReg) {
785 0 : const X86StateCell& cell = cells[dVReg->_raId];
786 0 : if (!sVd) {
787 0 : if (cell.getState() == VirtReg::kStateReg)
788 0 : continue;
789 :
790 0 : if (cell.getState() == VirtReg::kStateMem)
791 : self->spill<C>(dVReg);
792 : else
793 : self->unuse<C>(dVReg);
794 :
795 : didWork = true;
796 0 : continue;
797 : }
798 : else {
799 0 : if (cell.getState() == VirtReg::kStateReg) {
800 0 : if (dVReg->getPhysId() != Globals::kInvalidRegId && sVd->getPhysId() != Globals::kInvalidRegId) {
801 : if (C == X86Reg::kKindGp) {
802 : self->swapGp(dVReg, sVd);
803 : }
804 : else {
805 : self->spill<C>(dVReg);
806 : self->move<C>(sVd, physId);
807 : }
808 :
809 : didWork = true;
810 0 : continue;
811 : }
812 : else {
813 : didWork = true;
814 0 : continue;
815 : }
816 : }
817 :
818 0 : if (cell.getState() == VirtReg::kStateMem)
819 : self->spill<C>(dVReg);
820 : else
821 : self->unuse<C>(dVReg);
822 0 : goto _MoveOrLoad;
823 : }
824 : }
825 : }
826 : } while (didWork);
827 :
828 : uint32_t dModified = dst->_modified.get(C);
829 : uint32_t sModified = src->_modified.get(C);
830 :
831 0 : if (dModified != sModified) {
832 0 : for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
833 0 : VirtReg* vreg = dVars[physId];
834 0 : if (!vreg) continue;
835 :
836 0 : if ((dModified & regMask) && !(sModified & regMask)) {
837 : self->save<C>(vreg);
838 0 : continue;
839 : }
840 :
841 0 : if (!(dModified & regMask) && (sModified & regMask)) {
842 : self->modify<C>(vreg);
843 0 : continue;
844 : }
845 : }
846 : }
847 : }
848 :
849 0 : void X86RAPass::switchState(RAState* src_) {
850 : ASMJIT_ASSERT(src_ != nullptr);
851 :
852 : X86RAState* cur = getState();
853 : X86RAState* src = static_cast<X86RAState*>(src_);
854 :
855 : // Ignore if both states are equal.
856 0 : if (cur == src)
857 : return;
858 :
859 : // Switch variables.
860 : X86RAPass_switchStateVars<X86Reg::kKindGp >(this, src);
861 : X86RAPass_switchStateVars<X86Reg::kKindMm >(this, src);
862 : X86RAPass_switchStateVars<X86Reg::kKindVec>(this, src);
863 :
864 : // Calculate changed state.
865 : VirtReg** vregs = _contextVd.getData();
866 0 : uint32_t count = static_cast<uint32_t>(_contextVd.getLength());
867 :
868 : X86StateCell* cells = src->_cells;
869 0 : for (uint32_t i = 0; i < count; i++) {
870 0 : VirtReg* vreg = static_cast<VirtReg*>(vregs[i]);
871 0 : const X86StateCell& cell = cells[i];
872 : uint32_t vState = cell.getState();
873 :
874 0 : if (vState != VirtReg::kStateReg) {
875 : vreg->setState(vState);
876 : vreg->setModified(false);
877 : }
878 : }
879 :
880 : ASMJIT_X86_CHECK_STATE
881 : }
882 :
883 : // ============================================================================
884 : // [asmjit::X86RAPass - State - Intersect]
885 : // ============================================================================
886 :
887 : // The algorithm is actually not so smart, but tries to find an intersection od
888 : // `a` and `b` and tries to move/alloc a variable into that location if it's
889 : // possible. It also finds out which variables will be spilled/unused by `a`
890 : // and `b` and performs that action here. It may improve the switch state code
891 : // in certain cases, but doesn't necessarily do the best job possible.
892 : template<int C>
893 : static ASMJIT_INLINE void X86RAPass_intersectStateVars(X86RAPass* self, X86RAState* a, X86RAState* b) {
894 : X86RAState* dst = self->getState();
895 :
896 : VirtReg** dVars = dst->getListByKind(C);
897 : VirtReg** aVars = a->getListByKind(C);
898 :
899 0 : X86StateCell* aCells = a->_cells;
900 0 : X86StateCell* bCells = b->_cells;
901 :
902 : uint32_t regCount = self->_regCount.get(C);
903 : bool didWork;
904 :
905 : // Similar to `switchStateVars()`, we iterate over and over until there is
906 : // no work to be done.
907 0 : do {
908 : didWork = false;
909 :
910 0 : for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
911 0 : VirtReg* dVReg = dVars[physId]; // Destination reg.
912 0 : VirtReg* aVReg = aVars[physId]; // State-a reg.
913 :
914 0 : if (dVReg == aVReg) continue;
915 :
916 0 : if (dVReg) {
917 0 : const X86StateCell& aCell = aCells[dVReg->_raId];
918 0 : const X86StateCell& bCell = bCells[dVReg->_raId];
919 :
920 0 : if (aCell.getState() != VirtReg::kStateReg && bCell.getState() != VirtReg::kStateReg) {
921 0 : if (aCell.getState() == VirtReg::kStateMem || bCell.getState() == VirtReg::kStateMem)
922 : self->spill<C>(dVReg);
923 : else
924 : self->unuse<C>(dVReg);
925 :
926 : dVReg = nullptr;
927 : didWork = true;
928 0 : if (!aVReg) continue;
929 : }
930 : }
931 :
932 0 : if (!dVReg && aVReg) {
933 0 : if (aVReg->getPhysId() != Globals::kInvalidRegId)
934 : self->move<C>(aVReg, physId);
935 : else
936 : self->load<C>(aVReg, physId);
937 :
938 : didWork = true;
939 0 : continue;
940 : }
941 :
942 0 : if (dVReg) {
943 0 : const X86StateCell& aCell = aCells[dVReg->_raId];
944 0 : const X86StateCell& bCell = bCells[dVReg->_raId];
945 :
946 0 : if (!aVReg) {
947 0 : if (aCell.getState() == VirtReg::kStateReg || bCell.getState() == VirtReg::kStateReg)
948 0 : continue;
949 :
950 0 : if (aCell.getState() == VirtReg::kStateMem || bCell.getState() == VirtReg::kStateMem)
951 : self->spill<C>(dVReg);
952 : else
953 : self->unuse<C>(dVReg);
954 :
955 : didWork = true;
956 0 : continue;
957 : }
958 : else if (C == X86Reg::kKindGp) {
959 0 : if (aCell.getState() == VirtReg::kStateReg) {
960 0 : if (dVReg->getPhysId() != Globals::kInvalidRegId && aVReg->getPhysId() != Globals::kInvalidRegId) {
961 : self->swapGp(dVReg, aVReg);
962 :
963 : didWork = true;
964 0 : continue;
965 : }
966 : }
967 : }
968 : }
969 : }
970 : } while (didWork);
971 :
972 : uint32_t dModified = dst->_modified.get(C);
973 : uint32_t aModified = a->_modified.get(C);
974 :
975 0 : if (dModified != aModified) {
976 0 : for (uint32_t physId = 0, regMask = 0x1; physId < regCount; physId++, regMask <<= 1) {
977 0 : VirtReg* vreg = dVars[physId];
978 0 : if (!vreg) continue;
979 :
980 0 : const X86StateCell& aCell = aCells[vreg->_raId];
981 0 : if ((dModified & regMask) && !(aModified & regMask) && aCell.getState() == VirtReg::kStateReg)
982 : self->save<C>(vreg);
983 : }
984 : }
985 : }
986 :
987 0 : void X86RAPass::intersectStates(RAState* a_, RAState* b_) {
988 : X86RAState* a = static_cast<X86RAState*>(a_);
989 : X86RAState* b = static_cast<X86RAState*>(b_);
990 :
991 : ASMJIT_ASSERT(a != nullptr);
992 : ASMJIT_ASSERT(b != nullptr);
993 :
994 : X86RAPass_intersectStateVars<X86Reg::kKindGp >(this, a, b);
995 : X86RAPass_intersectStateVars<X86Reg::kKindMm >(this, a, b);
996 : X86RAPass_intersectStateVars<X86Reg::kKindVec>(this, a, b);
997 :
998 : ASMJIT_X86_CHECK_STATE
999 0 : }
1000 :
1001 : // ============================================================================
1002 : // [asmjit::X86RAPass - GetJccFlow / GetOppositeJccFlow]
1003 : // ============================================================================
1004 :
1005 : //! \internal
1006 : static ASMJIT_INLINE CBNode* X86RAPass_getJccFlow(CBJump* jNode) {
1007 0 : if (jNode->isTaken())
1008 0 : return jNode->getTarget();
1009 : else
1010 0 : return jNode->getNext();
1011 : }
1012 :
1013 : //! \internal
1014 : static ASMJIT_INLINE CBNode* X86RAPass_getOppositeJccFlow(CBJump* jNode) {
1015 0 : if (jNode->isTaken())
1016 0 : return jNode->getNext();
1017 : else
1018 0 : return jNode->getTarget();
1019 : }
1020 :
1021 : // ============================================================================
1022 : // [asmjit::X86RAPass - SingleVarInst]
1023 : // ============================================================================
1024 :
1025 : //! \internal
1026 252 : static void X86RAPass_prepareSingleVarInst(uint32_t instId, TiedReg* tr) {
1027 252 : switch (instId) {
1028 : // - andn reg, reg ; Set all bits in reg to 0.
1029 : // - xor/pxor reg, reg ; Set all bits in reg to 0.
1030 : // - sub/psub reg, reg ; Set all bits in reg to 0.
1031 : // - pcmpgt reg, reg ; Set all bits in reg to 0.
1032 : // - pcmpeq reg, reg ; Set all bits in reg to 1.
1033 252 : case X86Inst::kIdPandn :
1034 : case X86Inst::kIdXor : case X86Inst::kIdXorpd : case X86Inst::kIdXorps : case X86Inst::kIdPxor :
1035 : case X86Inst::kIdSub:
1036 : case X86Inst::kIdPsubb : case X86Inst::kIdPsubw : case X86Inst::kIdPsubd : case X86Inst::kIdPsubq :
1037 : case X86Inst::kIdPsubsb : case X86Inst::kIdPsubsw : case X86Inst::kIdPsubusb : case X86Inst::kIdPsubusw :
1038 : case X86Inst::kIdPcmpeqb : case X86Inst::kIdPcmpeqw : case X86Inst::kIdPcmpeqd : case X86Inst::kIdPcmpeqq :
1039 : case X86Inst::kIdPcmpgtb : case X86Inst::kIdPcmpgtw : case X86Inst::kIdPcmpgtd : case X86Inst::kIdPcmpgtq :
1040 252 : tr->flags &= ~TiedReg::kRReg;
1041 252 : break;
1042 :
1043 : // - and reg, reg ; Nop.
1044 : // - or reg, reg ; Nop.
1045 : // - xchg reg, reg ; Nop.
1046 0 : case X86Inst::kIdAnd : case X86Inst::kIdAndpd : case X86Inst::kIdAndps : case X86Inst::kIdPand :
1047 : case X86Inst::kIdOr : case X86Inst::kIdOrpd : case X86Inst::kIdOrps : case X86Inst::kIdPor :
1048 : case X86Inst::kIdXchg :
1049 0 : tr->flags &= ~TiedReg::kWReg;
1050 0 : break;
1051 : }
1052 252 : }
1053 :
1054 : // ============================================================================
1055 : // [asmjit::X86RAPass - Helpers]
1056 : // ============================================================================
1057 :
1058 1944 : static void X86RAPass_assignStackArgsRegId(X86RAPass* self, CCFunc* func) {
1059 : const FuncDetail& fd = func->getDetail();
1060 : FuncFrameInfo& ffi = func->getFrameInfo();
1061 :
1062 : // Select some register which will contain the base address of function
1063 : // arguments and return address. The algorithm tries to select registers
1064 : // which are saved or not preserved by default, if not successful it picks
1065 : // any other register and adds it to `_savedRegs`.
1066 : uint32_t stackArgsRegId;
1067 1944 : if (ffi.hasPreservedFP()) {
1068 : stackArgsRegId = X86Gp::kIdBp;
1069 : }
1070 : else {
1071 : // Passed registers as defined by the calling convention.
1072 : uint32_t passed = fd.getPassedRegs(X86Reg::kKindGp);
1073 :
1074 : // Registers actually used to pass function arguments (related to this
1075 : // function signature) with ESP|RSP included as this register can't be
1076 : // used in general to hold anything bug stack pointer.
1077 1944 : uint32_t used = fd.getUsedRegs(X86Reg::kKindGp) | Utils::mask(X86Gp::kIdSp);
1078 :
1079 : // First try register that is defined to pass a function argument by the
1080 : // calling convention, but is not used by this function. This will most
1081 : // likely fail in 32-bit mode, but there is a high chance that it will
1082 : // pass in 64-bit mode if the function doesn't use so many arguments.
1083 1944 : uint32_t regs = passed & ~used;
1084 :
1085 : // Pick any other register if that didn't work out.
1086 1944 : if (!regs) regs = ~passed & ~used;
1087 :
1088 : stackArgsRegId = Utils::findFirstBit(regs);
1089 : ASMJIT_ASSERT(stackArgsRegId < self->cc()->getGpCount());
1090 : }
1091 :
1092 : ffi.setStackArgsRegId(stackArgsRegId);
1093 1944 : }
1094 :
1095 : // ============================================================================
1096 : // [asmjit::X86RAPass - SArg Insertion]
1097 : // ============================================================================
1098 :
1099 : struct SArgData {
1100 : VirtReg* sVd;
1101 : VirtReg* cVd;
1102 : CCPushArg* sArg;
1103 : uint32_t aType;
1104 : };
1105 :
1106 : static ASMJIT_INLINE bool X86RAPass_mustConvertSArg(X86RAPass* self, uint32_t dstTypeId, uint32_t srcTypeId) noexcept{
1107 0 : uint32_t dstFloatSize = dstTypeId == TypeId::kF32 ? 4 :
1108 : dstTypeId == TypeId::kF64 ? 8 : 0;
1109 :
1110 0 : uint32_t srcFloatSize = srcTypeId == TypeId::kF32 ? 4 :
1111 : srcTypeId == TypeId::kF32x1 ? 4 :
1112 : srcTypeId == TypeId::kF64 ? 8 :
1113 : srcTypeId == TypeId::kF64x1 ? 8 : 0;
1114 :
1115 0 : if (dstFloatSize && srcFloatSize)
1116 : return dstFloatSize != srcFloatSize;
1117 : else
1118 : return false;
1119 : }
1120 :
1121 : static ASMJIT_INLINE uint32_t X86RAPass_typeOfConvertedSArg(X86RAPass* self, uint32_t dstTypeId, uint32_t srcTypeId) noexcept {
1122 : ASMJIT_ASSERT(X86RAPass_mustConvertSArg(self, dstTypeId, srcTypeId));
1123 0 : return dstTypeId == TypeId::kF32 ? TypeId::kF32x1 : TypeId::kF64x1;
1124 : }
1125 :
1126 : static ASMJIT_INLINE Error X86RAPass_insertPushArg(
1127 : X86RAPass* self, CCFuncCall* call,
1128 : VirtReg* sReg, const uint32_t* gaRegs,
1129 : const FuncDetail::Value& arg, uint32_t argIndex,
1130 : SArgData* sArgList, uint32_t& sArgCount) {
1131 :
1132 : X86Compiler* cc = self->cc();
1133 : uint32_t i;
1134 : uint32_t dstTypeId = arg.getTypeId();
1135 : uint32_t srcTypeId = sReg->getTypeId();
1136 :
1137 : // First locate or create sArgBase.
1138 0 : for (i = 0; i < sArgCount; i++)
1139 0 : if (sArgList[i].sVd == sReg && !sArgList[i].cVd)
1140 : break;
1141 :
1142 0 : SArgData* sArgData = &sArgList[i];
1143 0 : if (i == sArgCount) {
1144 0 : sArgData->sVd = sReg;
1145 0 : sArgData->cVd = nullptr;
1146 0 : sArgData->sArg = nullptr;
1147 0 : sArgData->aType = 0xFF;
1148 0 : sArgCount++;
1149 : }
1150 :
1151 : uint32_t srcRegKind = sReg->getKind();
1152 :
1153 : // Only handles float<->double conversion.
1154 0 : if (X86RAPass_mustConvertSArg(self, dstTypeId, srcTypeId)) {
1155 : uint32_t cvtTypeId = X86RAPass_typeOfConvertedSArg(self, dstTypeId, srcTypeId);
1156 : uint32_t cvtRegKind = X86Reg::kKindVec;
1157 :
1158 0 : while (++i < sArgCount) {
1159 0 : sArgData = &sArgList[i];
1160 0 : if (sArgData->sVd != sReg)
1161 : break;
1162 :
1163 0 : if (sArgData->cVd->getTypeId() != cvtTypeId || sArgData->aType != dstTypeId)
1164 0 : continue;
1165 :
1166 0 : sArgData->sArg->_args |= Utils::mask(argIndex);
1167 : return kErrorOk;
1168 : }
1169 :
1170 0 : VirtReg* cReg = cc->newVirtReg(dstTypeId, x86OpData.archRegs.regInfo[X86Reg::kRegXmm].getSignature(), nullptr);
1171 0 : if (!cReg) return DebugUtils::errored(kErrorNoHeapMemory);
1172 :
1173 : CCPushArg* sArg = cc->newNodeT<CCPushArg>(call, sReg, cReg);
1174 0 : if (!sArg) return DebugUtils::errored(kErrorNoHeapMemory);
1175 :
1176 : X86RAData* raData = self->newRAData(2);
1177 0 : if (!raData) return DebugUtils::errored(kErrorNoHeapMemory);
1178 :
1179 0 : ASMJIT_PROPAGATE(self->assignRAId(cReg));
1180 0 : ASMJIT_PROPAGATE(self->assignRAId(sReg));
1181 :
1182 0 : raData->tiedTotal = 2;
1183 : raData->tiedCount.reset();
1184 : raData->tiedCount.add(srcRegKind);
1185 : raData->tiedCount.add(cvtRegKind);
1186 :
1187 : raData->tiedIndex.reset();
1188 : raData->inRegs.reset();
1189 : raData->outRegs.reset();
1190 : raData->clobberedRegs.reset();
1191 :
1192 0 : if (srcRegKind <= cvtRegKind) {
1193 0 : raData->tiedArray[0].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
1194 0 : raData->tiedArray[1].init(cReg, TiedReg::kWReg, 0, gaRegs[cvtRegKind]);
1195 0 : raData->tiedIndex.set(cvtRegKind, srcRegKind != cvtRegKind);
1196 : }
1197 : else {
1198 0 : raData->tiedArray[0].init(cReg, TiedReg::kWReg, 0, gaRegs[cvtRegKind]);
1199 0 : raData->tiedArray[1].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
1200 : raData->tiedIndex.set(srcRegKind, 1);
1201 : }
1202 :
1203 : sArg->setPassData(raData);
1204 0 : sArg->_args |= Utils::mask(argIndex);
1205 :
1206 0 : cc->addBefore(sArg, call);
1207 0 : ::memmove(sArgData + 1, sArgData, (sArgCount - i) * sizeof(SArgData));
1208 :
1209 0 : sArgData->sVd = sReg;
1210 0 : sArgData->cVd = cReg;
1211 0 : sArgData->sArg = sArg;
1212 0 : sArgData->aType = dstTypeId;
1213 :
1214 0 : sArgCount++;
1215 : return kErrorOk;
1216 : }
1217 : else {
1218 0 : CCPushArg* sArg = sArgData->sArg;
1219 0 : ASMJIT_PROPAGATE(self->assignRAId(sReg));
1220 :
1221 0 : if (!sArg) {
1222 : sArg = cc->newNodeT<CCPushArg>(call, sReg, (VirtReg*)nullptr);
1223 0 : if (!sArg) return DebugUtils::errored(kErrorNoHeapMemory);
1224 :
1225 : X86RAData* raData = self->newRAData(1);
1226 0 : if (!raData) return DebugUtils::errored(kErrorNoHeapMemory);
1227 :
1228 : raData->tiedTotal = 1;
1229 : raData->tiedIndex.reset();
1230 : raData->tiedCount.reset();
1231 : raData->tiedCount.add(srcRegKind);
1232 : raData->inRegs.reset();
1233 : raData->outRegs.reset();
1234 : raData->clobberedRegs.reset();
1235 0 : raData->tiedArray[0].init(sReg, TiedReg::kRReg, 0, gaRegs[srcRegKind]);
1236 :
1237 : sArg->setPassData(raData);
1238 0 : sArgData->sArg = sArg;
1239 :
1240 0 : cc->addBefore(sArg, call);
1241 : }
1242 :
1243 0 : sArg->_args |= Utils::mask(argIndex);
1244 : return kErrorOk;
1245 : }
1246 : }
1247 :
1248 : // ============================================================================
1249 : // [asmjit::X86RAPass - Fetch]
1250 : // ============================================================================
1251 :
1252 : //! \internal
1253 : //!
1254 : //! Prepare the given function `func`.
1255 : //!
1256 : //! For each node:
1257 : //! - Create and assign groupId and position.
1258 : //! - Collect all variables and merge them to vaList.
1259 1944 : Error X86RAPass::fetch() {
1260 : uint32_t archType = cc()->getArchType();
1261 : CCFunc* func = getFunc();
1262 :
1263 : CBNode* node_ = func;
1264 : CBNode* next = nullptr;
1265 : CBNode* stop = getStop();
1266 :
1267 157464 : TiedReg agTmp[80];
1268 : SArgData sArgList[80];
1269 :
1270 : uint32_t position = 0;
1271 : ZoneList<CBNode*>::Link* jLink = nullptr;
1272 :
1273 : // Global allocable registers.
1274 1944 : uint32_t* gaRegs = _gaRegs;
1275 :
1276 1944 : if (func->getFrameInfo().hasPreservedFP())
1277 0 : gaRegs[X86Reg::kKindGp] &= ~Utils::mask(X86Gp::kIdBp);
1278 :
1279 : // Allowed index registers (GP/XMM/YMM).
1280 1944 : const uint32_t indexMask = Utils::bits(_regCount.getGp()) & ~(Utils::mask(4));
1281 :
1282 : // --------------------------------------------------------------------------
1283 : // [VI Macros]
1284 : // --------------------------------------------------------------------------
1285 :
1286 : #define RA_POPULATE(NODE) \
1287 : do { \
1288 : X86RAData* raData = newRAData(0); \
1289 : if (!raData) goto NoMem; \
1290 : NODE->setPassData(raData); \
1291 : } while (0)
1292 :
1293 : #define RA_DECLARE() \
1294 : do { \
1295 : X86RegCount tiedCount; \
1296 : X86RegCount tiedIndex; \
1297 : uint32_t tiedTotal = 0; \
1298 : \
1299 : X86RegMask inRegs; \
1300 : X86RegMask outRegs; \
1301 : X86RegMask clobberedRegs; \
1302 : \
1303 : tiedCount.reset(); \
1304 : inRegs.reset(); \
1305 : outRegs.reset(); \
1306 : clobberedRegs.reset()
1307 :
1308 : #define RA_FINALIZE(NODE) \
1309 : { \
1310 : X86RAData* raData = newRAData(tiedTotal); \
1311 : if (!raData) goto NoMem; \
1312 : \
1313 : tiedIndex.indexFromRegCount(tiedCount); \
1314 : raData->tiedCount = tiedCount; \
1315 : raData->tiedIndex = tiedIndex; \
1316 : \
1317 : raData->inRegs = inRegs; \
1318 : raData->outRegs = outRegs; \
1319 : raData->clobberedRegs = clobberedRegs; \
1320 : \
1321 : TiedReg* tied = agTmp; \
1322 : while (tiedTotal) { \
1323 : VirtReg* vreg = tied->vreg; \
1324 : \
1325 : uint32_t _kind = vreg->getKind(); \
1326 : uint32_t _index = tiedIndex.get(_kind); \
1327 : \
1328 : tiedIndex.add(_kind); \
1329 : if (tied->inRegs) \
1330 : tied->allocableRegs = tied->inRegs; \
1331 : else if (tied->outPhysId != Globals::kInvalidRegId) \
1332 : tied->allocableRegs = Utils::mask(tied->outPhysId); \
1333 : else \
1334 : tied->allocableRegs &= ~inRegs.get(_kind); \
1335 : \
1336 : vreg->_tied = nullptr; \
1337 : raData->setTiedAt(_index, *tied); \
1338 : \
1339 : tied++; \
1340 : tiedTotal--; \
1341 : } \
1342 : NODE->setPassData(raData); \
1343 : } \
1344 : } while (0)
1345 :
1346 : #define RA_INSERT(REG, TIED, FLAGS, NEW_ALLOCABLE) \
1347 : do { \
1348 : ASMJIT_ASSERT(REG->_tied == nullptr); \
1349 : TIED = &agTmp[tiedTotal++]; \
1350 : TIED->init(REG, FLAGS, 0, NEW_ALLOCABLE); \
1351 : TIED->refCount++; \
1352 : REG->_tied = TIED; \
1353 : \
1354 : if (assignRAId(REG) != kErrorOk) goto NoMem; \
1355 : tiedCount.add(REG->getKind()); \
1356 : } while (0)
1357 :
1358 : #define RA_MERGE(REG, TIED, FLAGS, NEW_ALLOCABLE) \
1359 : do { \
1360 : TIED = REG->_tied; \
1361 : \
1362 : if (!TIED) { \
1363 : TIED = &agTmp[tiedTotal++]; \
1364 : TIED->init(REG, 0, 0, NEW_ALLOCABLE); \
1365 : REG->_tied = TIED; \
1366 : \
1367 : if (assignRAId(REG) != kErrorOk) goto NoMem; \
1368 : tiedCount.add(REG->getKind()); \
1369 : } \
1370 : \
1371 : TIED->flags |= FLAGS; \
1372 : TIED->refCount++; \
1373 : } while (0)
1374 :
1375 : // --------------------------------------------------------------------------
1376 : // [Loop]
1377 : // --------------------------------------------------------------------------
1378 :
1379 : do {
1380 34686 : _Do:
1381 36630 : while (node_->hasPassData()) {
1382 0 : _NextGroup:
1383 1944 : if (!jLink)
1384 : jLink = _jccList.getFirst();
1385 : else
1386 : jLink = jLink->getNext();
1387 :
1388 1944 : if (!jLink) goto _Done;
1389 : node_ = X86RAPass_getOppositeJccFlow(static_cast<CBJump*>(jLink->getValue()));
1390 : }
1391 :
1392 36630 : position++;
1393 :
1394 : next = node_->getNext();
1395 : node_->setPosition(position);
1396 :
1397 36630 : switch (node_->getType()) {
1398 : // ----------------------------------------------------------------------
1399 : // [Align/Embed]
1400 : // ----------------------------------------------------------------------
1401 :
1402 : case CBNode::kNodeAlign:
1403 : case CBNode::kNodeData:
1404 : default:
1405 0 : RA_POPULATE(node_);
1406 : break;
1407 :
1408 : // ----------------------------------------------------------------------
1409 : // [Hint]
1410 : // ----------------------------------------------------------------------
1411 :
1412 0 : case CBNode::kNodeHint: {
1413 : CCHint* node = static_cast<CCHint*>(node_);
1414 : RA_DECLARE();
1415 :
1416 0 : if (node->getHint() == CCHint::kHintAlloc) {
1417 : uint32_t remain[Globals::kMaxVRegKinds];
1418 : CCHint* cur = node;
1419 :
1420 0 : remain[X86Reg::kKindGp ] = _regCount.getGp() - 1 - func->getFrameInfo().hasPreservedFP();
1421 0 : remain[X86Reg::kKindMm ] = _regCount.getMm();
1422 0 : remain[X86Reg::kKindK ] = _regCount.getK();
1423 0 : remain[X86Reg::kKindVec] = _regCount.getVec();
1424 :
1425 : // Merge as many alloc-hints as possible.
1426 : for (;;) {
1427 : VirtReg* vreg = static_cast<VirtReg*>(cur->getVReg());
1428 0 : TiedReg* tied = vreg->_tied;
1429 :
1430 : uint32_t kind = vreg->getKind();
1431 : uint32_t physId = cur->getValue();
1432 : uint32_t regMask = 0;
1433 :
1434 : // We handle both kInvalidReg and kInvalidValue.
1435 0 : if (physId < Globals::kInvalidRegId)
1436 : regMask = Utils::mask(physId);
1437 :
1438 0 : if (!tied) {
1439 0 : if (inRegs.has(kind, regMask) || remain[kind] == 0)
1440 : break;
1441 0 : RA_INSERT(vreg, tied, TiedReg::kRReg, gaRegs[kind]);
1442 :
1443 0 : if (regMask != 0) {
1444 : inRegs.xor_(kind, regMask);
1445 0 : tied->inRegs = regMask;
1446 : tied->setInPhysId(physId);
1447 : }
1448 0 : remain[kind]--;
1449 : }
1450 0 : else if (regMask != 0) {
1451 0 : if (inRegs.has(kind, regMask) && tied->inRegs != regMask)
1452 : break;
1453 :
1454 0 : inRegs.xor_(kind, tied->inRegs | regMask);
1455 0 : tied->inRegs = regMask;
1456 : tied->setInPhysId(physId);
1457 : }
1458 :
1459 0 : if (cur != node)
1460 0 : cc()->removeNode(cur);
1461 :
1462 : cur = static_cast<CCHint*>(node->getNext());
1463 0 : if (!cur || cur->getType() != CBNode::kNodeHint || cur->getHint() != CCHint::kHintAlloc)
1464 : break;
1465 : }
1466 :
1467 : next = node->getNext();
1468 : }
1469 : else {
1470 : VirtReg* vreg = static_cast<VirtReg*>(node->getVReg());
1471 : TiedReg* tied;
1472 :
1473 : uint32_t flags = 0;
1474 : switch (node->getHint()) {
1475 0 : case CCHint::kHintSpill : flags = TiedReg::kRMem | TiedReg::kSpill; break;
1476 0 : case CCHint::kHintSave : flags = TiedReg::kRMem ; break;
1477 0 : case CCHint::kHintSaveAndUnuse: flags = TiedReg::kRMem | TiedReg::kUnuse; break;
1478 0 : case CCHint::kHintUnuse : flags = TiedReg::kUnuse ; break;
1479 : }
1480 0 : RA_INSERT(vreg, tied, flags, 0);
1481 : }
1482 :
1483 0 : RA_FINALIZE(node_);
1484 0 : break;
1485 : }
1486 :
1487 : // ----------------------------------------------------------------------
1488 : // [Label]
1489 : // ----------------------------------------------------------------------
1490 :
1491 : case CBNode::kNodeLabel: {
1492 0 : RA_POPULATE(node_);
1493 0 : if (node_ == func->getExitNode()) {
1494 0 : ASMJIT_PROPAGATE(addReturningNode(node_));
1495 0 : goto _NextGroup;
1496 : }
1497 : break;
1498 : }
1499 :
1500 : // ----------------------------------------------------------------------
1501 : // [Inst]
1502 : // ----------------------------------------------------------------------
1503 :
1504 31106 : case CBNode::kNodeInst: {
1505 : CBInst* node = static_cast<CBInst*>(node_);
1506 :
1507 : uint32_t instId = node->getInstId();
1508 : uint32_t flags = node->getFlags();
1509 : uint32_t options = node->getOptions();
1510 : uint32_t gpAllowedMask = 0xFFFFFFFF;
1511 :
1512 : Operand* opArray = node->getOpArray();
1513 : uint32_t opCount = node->getOpCount();
1514 :
1515 : RA_DECLARE();
1516 31106 : if (opCount) {
1517 : const X86Inst& inst = X86Inst::getInst(instId);
1518 : const X86Inst::CommonData& commonData = inst.getCommonData();
1519 : const X86SpecialInst* special = nullptr;
1520 :
1521 : // Collect instruction flags and merge all 'TiedReg's.
1522 31106 : if (commonData.isFpu())
1523 : flags |= CBNode::kFlagIsFp;
1524 :
1525 31106 : if (commonData.hasFixedRM() && (special = X86SpecialInst_get(instId, opArray, opCount)) != nullptr)
1526 0 : flags |= CBNode::kFlagIsSpecial;
1527 :
1528 93438 : for (uint32_t i = 0; i < opCount; i++) {
1529 62332 : Operand* op = &opArray[i];
1530 : VirtReg* vreg;
1531 : TiedReg* tied;
1532 :
1533 : if (op->isVirtReg()) {
1534 : vreg = cc()->getVirtRegById(op->getId());
1535 48896 : if (vreg->isFixed()) continue;
1536 :
1537 119644 : RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
1538 48896 : if (static_cast<X86Reg*>(op)->isGpb()) {
1539 0 : tied->flags |= static_cast<X86Gp*>(op)->isGpbLo() ? TiedReg::kX86GpbLo : TiedReg::kX86GpbHi;
1540 0 : if (archType == ArchInfo::kTypeX86) {
1541 : // If a byte register is accessed in 32-bit mode we have to limit
1542 : // all allocable registers for that variable to eax/ebx/ecx/edx.
1543 : // Other variables are not affected.
1544 0 : tied->allocableRegs &= 0x0F;
1545 : }
1546 : else {
1547 : // It's fine if lo-byte register is accessed in 64-bit mode;
1548 : // however, hi-byte has to be checked and if it's used all
1549 : // registers (GP/XMM) could be only allocated in the lower eight
1550 : // half. To do that, we patch 'allocableRegs' of all variables
1551 : // we collected until now and change the allocable restriction
1552 : // for variables that come after.
1553 0 : if (static_cast<X86Gp*>(op)->isGpbHi()) {
1554 0 : tied->allocableRegs &= 0x0F;
1555 0 : if (gpAllowedMask != 0xFF) {
1556 0 : for (uint32_t j = 0; j < i; j++)
1557 0 : agTmp[j].allocableRegs &= (agTmp[j].flags & TiedReg::kX86GpbHi) ? 0x0F : 0xFF;
1558 : gpAllowedMask = 0xFF;
1559 : }
1560 : }
1561 : }
1562 : }
1563 :
1564 48896 : if (special) {
1565 0 : uint32_t inReg = special[i].inReg;
1566 0 : uint32_t outReg = special[i].outReg;
1567 : uint32_t c;
1568 :
1569 0 : if (static_cast<const X86Reg*>(op)->isGp())
1570 : c = X86Reg::kKindGp;
1571 : else
1572 : c = X86Reg::kKindVec;
1573 :
1574 0 : if (inReg != Globals::kInvalidRegId) {
1575 : uint32_t mask = Utils::mask(inReg);
1576 : inRegs.or_(c, mask);
1577 0 : tied->inRegs |= mask;
1578 : }
1579 :
1580 0 : if (outReg != Globals::kInvalidRegId) {
1581 : uint32_t mask = Utils::mask(outReg);
1582 : outRegs.or_(c, mask);
1583 : tied->setOutPhysId(outReg);
1584 : }
1585 :
1586 0 : tied->flags |= special[i].flags;
1587 : }
1588 : else {
1589 : uint32_t inFlags = TiedReg::kRReg;
1590 : uint32_t outFlags = TiedReg::kWReg;
1591 : uint32_t combinedFlags;
1592 :
1593 48896 : if (i == 0) {
1594 : // Read/Write is usually the combination of the first operand.
1595 : combinedFlags = inFlags | outFlags;
1596 :
1597 30864 : if (node->getOptions() & CodeEmitter::kOptionOverwrite) {
1598 : // Manually forcing write-only.
1599 : combinedFlags = outFlags;
1600 : }
1601 30864 : else if (commonData.isUseW()) {
1602 : // Write-only instruction.
1603 : uint32_t movSize = commonData.getWriteSize();
1604 : uint32_t regSize = vreg->getSize();
1605 :
1606 : // Exception - If the source operand is a memory location
1607 : // promote move size into 16 bytes.
1608 21852 : if (opArray[1].isMem() && inst.getOperationData().isMovSsSd())
1609 : movSize = 16;
1610 :
1611 21852 : if (static_cast<const X86Reg*>(op)->isGp()) {
1612 : uint32_t opSize = static_cast<const X86Reg*>(op)->getSize();
1613 :
1614 : // Move size is zero in case that it should be determined
1615 : // from the destination register.
1616 7248 : if (movSize == 0)
1617 : movSize = opSize;
1618 :
1619 : // Handle the case that a 32-bit operation in 64-bit mode
1620 : // always clears the rest of the destination register and
1621 : // the case that move size is actually greater than or
1622 : // equal to the size of the variable.
1623 7248 : if (movSize >= 4 || movSize >= regSize)
1624 : combinedFlags = outFlags;
1625 : }
1626 14604 : else if (movSize == 0 || movSize >= regSize) {
1627 : // If move size is greater than or equal to the size of
1628 : // the variable there is nothing to do, because the move
1629 : // will overwrite the variable in all cases.
1630 : combinedFlags = outFlags;
1631 : }
1632 : }
1633 9012 : else if (commonData.isUseR()) {
1634 : // Comparison/Test instructions don't modify any operand.
1635 : combinedFlags = inFlags;
1636 : }
1637 9012 : else if (instId == X86Inst::kIdImul && opCount == 3) {
1638 : // Imul.
1639 : combinedFlags = outFlags;
1640 : }
1641 : }
1642 : else {
1643 : // Read-Only is usually the combination of the second/third/fourth operands.
1644 : combinedFlags = inFlags;
1645 :
1646 : // Idiv is a special instruction, never handled here.
1647 : ASMJIT_ASSERT(instId != X86Inst::kIdIdiv);
1648 :
1649 : // Xchg/Xadd/Imul.
1650 18032 : if (commonData.isUseXX() || (instId == X86Inst::kIdImul && opCount == 3 && i == 1))
1651 : combinedFlags = inFlags | outFlags;
1652 : }
1653 48896 : tied->flags |= combinedFlags;
1654 : }
1655 : }
1656 13436 : else if (op->isMem()) {
1657 : X86Mem* m = static_cast<X86Mem*>(op);
1658 : node->setMemOpIndex(i);
1659 :
1660 6068 : uint32_t specBase = special ? uint32_t(special[i].inReg) : uint32_t(Globals::kInvalidRegId);
1661 :
1662 6068 : if (m->hasBaseReg()) {
1663 : uint32_t id = m->getBaseId();
1664 6068 : if (cc()->isVirtRegValid(id)) {
1665 : vreg = cc()->getVirtRegById(id);
1666 6068 : if (!vreg->isStack() && !vreg->isFixed()) {
1667 12136 : RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
1668 6068 : if (m->isRegHome()) {
1669 : uint32_t inFlags = TiedReg::kRMem;
1670 : uint32_t outFlags = TiedReg::kWMem;
1671 : uint32_t combinedFlags;
1672 :
1673 0 : if (i == 0) {
1674 : // Default for the first operand.
1675 : combinedFlags = inFlags | outFlags;
1676 :
1677 0 : if (commonData.isUseW()) {
1678 : // Move to memory - setting the right flags is important
1679 : // as if it's just move to the register. It's just a bit
1680 : // simpler as there are no special cases.
1681 0 : uint32_t movSize = std::max<uint32_t>(commonData.getWriteSize(), m->getSize());
1682 : uint32_t regSize = vreg->getSize();
1683 :
1684 0 : if (movSize >= regSize)
1685 : combinedFlags = outFlags;
1686 : }
1687 0 : else if (commonData.isUseR()) {
1688 : // Comparison/Test instructions don't modify any operand.
1689 : combinedFlags = inFlags;
1690 : }
1691 : }
1692 : else {
1693 : // Default for the second operand.
1694 : combinedFlags = inFlags;
1695 :
1696 : // Handle Xchg instruction (modifies both operands).
1697 0 : if (commonData.isUseXX())
1698 : combinedFlags = inFlags | outFlags;
1699 : }
1700 :
1701 0 : tied->flags |= combinedFlags;
1702 : }
1703 : else {
1704 6068 : if (specBase != Globals::kInvalidRegId) {
1705 : uint32_t mask = Utils::mask(specBase);
1706 : inRegs.or_(vreg->getKind(), mask);
1707 : outRegs.or_(vreg->getKind(), mask);
1708 0 : tied->inRegs |= mask;
1709 : tied->setOutPhysId(specBase);
1710 0 : tied->flags |= special[i].flags;
1711 : }
1712 : else {
1713 6068 : tied->flags |= TiedReg::kRReg;
1714 : }
1715 : }
1716 : }
1717 : }
1718 : }
1719 :
1720 6068 : if (m->hasIndexReg()) {
1721 : uint32_t id = m->getIndexId();
1722 0 : if (cc()->isVirtRegValid(id)) {
1723 : // Restrict allocation to all registers except ESP|RSP.
1724 : vreg = cc()->getVirtRegById(m->getIndexId());
1725 0 : if (!vreg->isFixed()) {
1726 : // TODO: AVX vector operands support.
1727 0 : RA_MERGE(vreg, tied, 0, gaRegs[X86Reg::kKindGp] & gpAllowedMask);
1728 0 : tied->allocableRegs &= indexMask;
1729 0 : tied->flags |= TiedReg::kRReg;
1730 : }
1731 : }
1732 : }
1733 : }
1734 : }
1735 :
1736 : node->setFlags(flags);
1737 31106 : if (tiedTotal) {
1738 : // Handle instructions which result in zeros/ones or nop if used with the
1739 : // same destination and source operand.
1740 31358 : if (tiedTotal == 1 && opCount >= 2 && opArray[0].isVirtReg() && opArray[1].isVirtReg() && !node->hasMemOp())
1741 252 : X86RAPass_prepareSingleVarInst(instId, &agTmp[0]);
1742 : }
1743 :
1744 : // Turn on AVX if the instruction operates on XMM|YMM|ZMM registers and uses VEX|EVEX prefix.
1745 31106 : if (tiedCount.getVec() && commonData.hasFlag(X86Inst::kFlagVex | X86Inst::kFlagEvex))
1746 0 : _avxEnabled = true;
1747 : }
1748 :
1749 : const RegOnly& extraReg = node->getExtraReg();
1750 31106 : if (extraReg.isValid()) {
1751 : uint32_t id = extraReg.getId();
1752 0 : if (cc()->isVirtRegValid(id)) {
1753 : VirtReg* vreg = cc()->getVirtRegById(id);
1754 : TiedReg* tied;
1755 0 : RA_MERGE(vreg, tied, 0, gaRegs[vreg->getKind()] & gpAllowedMask);
1756 :
1757 0 : if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) {
1758 0 : tied->allocableRegs = Utils::mask(X86Gp::kIdCx);
1759 0 : tied->flags |= TiedReg::kXReg;
1760 : }
1761 : else {
1762 0 : tied->flags |= TiedReg::kRReg;
1763 : }
1764 : }
1765 : }
1766 :
1767 85818 : RA_FINALIZE(node_);
1768 :
1769 : // Handle conditional/unconditional jump.
1770 31106 : if (node->isJmpOrJcc()) {
1771 : CBJump* jNode = static_cast<CBJump*>(node);
1772 : CBLabel* jTarget = jNode->getTarget();
1773 :
1774 : // If this jump is unconditional we put next node to unreachable node
1775 : // list so we can eliminate possible dead code. We have to do this in
1776 : // all cases since we are unable to translate without fetch() step.
1777 : //
1778 : // We also advance our node pointer to the target node to simulate
1779 : // natural flow of the function.
1780 0 : if (jNode->isJmp()) {
1781 0 : if (next && !next->hasPassData())
1782 0 : ASMJIT_PROPAGATE(addUnreachableNode(next));
1783 :
1784 : // Jump not followed.
1785 0 : if (!jTarget) {
1786 0 : ASMJIT_PROPAGATE(addReturningNode(jNode));
1787 0 : goto _NextGroup;
1788 : }
1789 :
1790 : node_ = jTarget;
1791 0 : goto _Do;
1792 : }
1793 : else {
1794 : // Jump not followed.
1795 0 : if (!jTarget) break;
1796 :
1797 0 : if (jTarget->hasPassData()) {
1798 : uint32_t jTargetPosition = jTarget->getPosition();
1799 :
1800 : // Update CBNode::kFlagIsTaken to true if this is a conditional
1801 : // backward jump. This behavior can be overridden by using
1802 : // `X86Inst::kOptionTaken` when the instruction is created.
1803 0 : if (!jNode->isTaken() && opCount == 1 && jTargetPosition <= position) {
1804 0 : jNode->_flags |= CBNode::kFlagIsTaken;
1805 : }
1806 : }
1807 0 : else if (next->hasPassData()) {
1808 : node_ = jTarget;
1809 0 : goto _Do;
1810 : }
1811 : else {
1812 0 : ASMJIT_PROPAGATE(addJccNode(jNode));
1813 : node_ = X86RAPass_getJccFlow(jNode);
1814 0 : goto _Do;
1815 : }
1816 : }
1817 : }
1818 : break;
1819 : }
1820 :
1821 : // ----------------------------------------------------------------------
1822 : // [Func-Entry]
1823 : // ----------------------------------------------------------------------
1824 :
1825 1944 : case CBNode::kNodeFunc: {
1826 : ASMJIT_ASSERT(node_ == func);
1827 1944 : X86RAPass_assignStackArgsRegId(this, func);
1828 :
1829 : FuncDetail& fd = func->getDetail();
1830 : TiedReg* tied;
1831 :
1832 : RA_DECLARE();
1833 1944 : cc()->setCursor(node_);
1834 :
1835 : X86Gp saReg;
1836 : uint32_t argCount = fd.getArgCount();
1837 :
1838 1944 : for (uint32_t i = 0; i < argCount; i++) {
1839 0 : const FuncDetail::Value& arg = fd.getArg(i);
1840 :
1841 : VirtReg* vReg = func->getArg(i);
1842 0 : if (!vReg) continue;
1843 :
1844 : // Overlapped function arguments.
1845 0 : if (vReg->_tied)
1846 0 : return DebugUtils::errored(kErrorOverlappedRegs);
1847 :
1848 : uint32_t aKind = X86Reg::kindOf(arg.getRegType());
1849 : uint32_t vKind = vReg->getKind();
1850 :
1851 0 : if (arg.byReg()) {
1852 0 : if (aKind == vKind) {
1853 0 : RA_INSERT(vReg, tied, TiedReg::kWReg, 0);
1854 : tied->setOutPhysId(arg.getRegId());
1855 : }
1856 : else {
1857 0 : X86Reg rTmp = cc()->newReg(arg.getTypeId(), "arg%u", i);
1858 : VirtReg* vTmp = cc()->getVirtReg(rTmp);
1859 :
1860 0 : RA_INSERT(vTmp, tied, TiedReg::kWReg, 0);
1861 : tied->setOutPhysId(arg.getRegId());
1862 :
1863 : X86Reg dstReg(X86Reg::fromSignature(vReg->getSignature(), vReg->getId()));
1864 : X86Reg srcReg(X86Reg::fromSignature(vTmp->getSignature(), vTmp->getId()));
1865 :
1866 : // Emit conversion after the prolog.
1867 0 : return X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(cc()),
1868 : dstReg, vReg->getTypeId(),
1869 0 : srcReg, vTmp->getTypeId(), _avxEnabled);
1870 : }
1871 : }
1872 : else {
1873 : // Instead of complicating the prolog allocation we create a virtual
1874 : // register that holds the base address to all arguments passed by
1875 : // stack and then insert nodes that copy these arguments to registers.
1876 0 : if (!saReg.isValid()) {
1877 0 : saReg = cc()->newGpz("__args");
1878 0 : if (!saReg.isValid()) goto NoMem;
1879 :
1880 : VirtReg* saBase = cc()->getVirtReg(saReg);
1881 0 : RA_INSERT(saBase, tied, TiedReg::kWReg, 0);
1882 :
1883 0 : if (func->getFrameInfo().hasPreservedFP())
1884 0 : saBase->_isFixed = true;
1885 : tied->setOutPhysId(func->getFrameInfo().getStackArgsRegId());
1886 : }
1887 :
1888 : // Argument passed by stack is handled after the prolog.
1889 : X86Gp aReg = X86Gp::fromSignature(vReg->getSignature(), vReg->getId());
1890 : X86Mem aMem = x86::ptr(saReg, arg.getStackOffset());
1891 : aMem.setArgHome();
1892 :
1893 0 : ASMJIT_PROPAGATE(
1894 : X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(cc()),
1895 : aReg, vReg->getTypeId(), aMem, arg.getTypeId(), _avxEnabled));
1896 : }
1897 : }
1898 :
1899 : // If saReg is not needed, clear it also from FuncFrameInfo.
1900 1944 : if (!saReg.isValid())
1901 : func->getFrameInfo().setStackArgsRegId(Globals::kInvalidRegId);
1902 :
1903 1944 : RA_FINALIZE(node_);
1904 : next = node_->getNext();
1905 1944 : break;
1906 : }
1907 :
1908 : // ----------------------------------------------------------------------
1909 : // [End]
1910 : // ----------------------------------------------------------------------
1911 :
1912 : case CBNode::kNodeSentinel: {
1913 0 : RA_POPULATE(node_);
1914 0 : ASMJIT_PROPAGATE(addReturningNode(node_));
1915 0 : goto _NextGroup;
1916 : }
1917 :
1918 : // ----------------------------------------------------------------------
1919 : // [Func-Exit]
1920 : // ----------------------------------------------------------------------
1921 :
1922 1944 : case CBNode::kNodeFuncExit: {
1923 : CCFuncRet* node = static_cast<CCFuncRet*>(node_);
1924 1944 : ASMJIT_PROPAGATE(addReturningNode(node));
1925 :
1926 : FuncDetail& fd = func->getDetail();
1927 : RA_DECLARE();
1928 :
1929 1944 : if (fd.hasRet()) {
1930 : const FuncDetail::Value& ret = fd.getRet(0);
1931 : uint32_t retKind = X86Reg::kindOf(ret.getRegType());
1932 :
1933 5832 : for (uint32_t i = 0; i < 2; i++) {
1934 : Operand_* op = &node->_ret[i];
1935 : if (op->isVirtReg()) {
1936 : VirtReg* vreg = cc()->getVirtRegById(op->getId());
1937 : TiedReg* tied;
1938 3888 : RA_MERGE(vreg, tied, 0, 0);
1939 :
1940 1944 : if (retKind == vreg->getKind()) {
1941 1944 : tied->flags |= TiedReg::kRReg;
1942 1944 : tied->inRegs = Utils::mask(ret.getRegId());
1943 : inRegs.or_(retKind, tied->inRegs);
1944 : }
1945 0 : else if (retKind == X86Reg::kKindFp) {
1946 0 : uint32_t fldFlag = ret.getTypeId() == TypeId::kF32 ? TiedReg::kX86Fld4 : TiedReg::kX86Fld8;
1947 0 : tied->flags |= TiedReg::kRMem | fldFlag;
1948 : }
1949 : else {
1950 : // TODO: Fix possible other return type conversions.
1951 0 : ASMJIT_NOT_REACHED();
1952 : }
1953 : }
1954 : }
1955 : }
1956 3888 : RA_FINALIZE(node_);
1957 :
1958 1944 : if (!next->hasPassData())
1959 1944 : ASMJIT_PROPAGATE(addUnreachableNode(next));
1960 1944 : goto _NextGroup;
1961 : }
1962 :
1963 : // ----------------------------------------------------------------------
1964 : // [Func-Call]
1965 : // ----------------------------------------------------------------------
1966 :
1967 1636 : case CBNode::kNodeFuncCall: {
1968 : CCFuncCall* node = static_cast<CCFuncCall*>(node_);
1969 : FuncDetail& fd = node->getDetail();
1970 :
1971 1636 : Operand_* target = node->_opArray;
1972 1636 : Operand_* args = node->_args;
1973 1636 : Operand_* rets = node->_ret;
1974 :
1975 : func->getFrameInfo().enableCalls();
1976 1636 : func->getFrameInfo().mergeCallFrameSize(fd.getArgStackSize());
1977 : // TODO: Each function frame should also define its stack arguments' alignment.
1978 : // func->getFrameInfo().mergeCallFrameAlignment();
1979 :
1980 : uint32_t i;
1981 : uint32_t argCount = fd.getArgCount();
1982 : uint32_t sArgCount = 0;
1983 1636 : uint32_t gpAllocableMask = gaRegs[X86Reg::kKindGp] & ~node->getDetail().getUsedRegs(X86Reg::kKindGp);
1984 :
1985 : VirtReg* vreg;
1986 : TiedReg* tied;
1987 :
1988 : RA_DECLARE();
1989 :
1990 : // Function-call operand.
1991 : if (target->isVirtReg()) {
1992 : vreg = cc()->getVirtRegById(target->getId());
1993 1636 : RA_MERGE(vreg, tied, 0, 0);
1994 :
1995 1636 : tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
1996 1636 : if (tied->inRegs == 0)
1997 1636 : tied->allocableRegs |= gpAllocableMask;
1998 : }
1999 0 : else if (target->isMem()) {
2000 : X86Mem* m = static_cast<X86Mem*>(target);
2001 :
2002 0 : if (m->hasBaseReg() && Operand::isPackedId(m->getBaseId())) {
2003 : vreg = cc()->getVirtRegById(m->getBaseId());
2004 0 : if (!vreg->isStack()) {
2005 0 : RA_MERGE(vreg, tied, 0, 0);
2006 0 : if (m->isRegHome()) {
2007 0 : tied->flags |= TiedReg::kRMem | TiedReg::kRCall;
2008 : }
2009 : else {
2010 0 : tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
2011 0 : if (tied->inRegs == 0)
2012 0 : tied->allocableRegs |= gpAllocableMask;
2013 : }
2014 : }
2015 : }
2016 :
2017 0 : if (m->hasIndexReg() && Operand::isPackedId(m->getIndexId())) {
2018 : // Restrict allocation to all registers except ESP/RSP.
2019 : vreg = cc()->getVirtRegById(m->getIndexId());
2020 0 : RA_MERGE(vreg, tied, 0, 0);
2021 :
2022 0 : tied->flags |= TiedReg::kRReg | TiedReg::kRCall;
2023 0 : if ((tied->inRegs & ~indexMask) == 0)
2024 0 : tied->allocableRegs &= gpAllocableMask & indexMask;
2025 : }
2026 : }
2027 :
2028 : // Function-call arguments.
2029 3486 : for (i = 0; i < argCount; i++) {
2030 1850 : Operand_* op = &args[i];
2031 404 : if (!op->isVirtReg()) continue;
2032 :
2033 : vreg = cc()->getVirtRegById(op->getId());
2034 : const FuncDetail::Value& arg = fd.getArg(i);
2035 :
2036 1446 : if (arg.byReg()) {
2037 2892 : RA_MERGE(vreg, tied, 0, 0);
2038 :
2039 : uint32_t argClass = X86Reg::kindOf(arg.getRegType());
2040 :
2041 1446 : if (vreg->getKind() == argClass) {
2042 1446 : tied->inRegs |= Utils::mask(arg.getRegId());
2043 1446 : tied->flags |= TiedReg::kRReg | TiedReg::kRFunc;
2044 : }
2045 : else {
2046 : // TODO: Function-call argument conversion.
2047 : }
2048 : }
2049 : // If this is a stack-based argument we insert CCPushArg instead of
2050 : // using TiedReg. It improves the code, because the argument can be
2051 : // moved onto stack as soon as it is ready and the register used by
2052 : // the variable can be reused for something else. It is also much
2053 : // easier to handle argument conversions, because there will be at
2054 : // most only one node per conversion.
2055 : else {
2056 0 : if (X86RAPass_insertPushArg(this, node, vreg, gaRegs, arg, i, sArgList, sArgCount) != kErrorOk)
2057 0 : goto NoMem;
2058 : }
2059 : }
2060 :
2061 : // Function-call returns.
2062 4908 : for (i = 0; i < 2; i++) {
2063 3272 : Operand_* op = &rets[i];
2064 1636 : if (!op->isVirtReg()) continue;
2065 :
2066 : const FuncDetail::Value& ret = fd.getRet(i);
2067 1636 : if (ret.byReg()) {
2068 : uint32_t retKind = X86Reg::kindOf(ret.getRegType());
2069 :
2070 : vreg = cc()->getVirtRegById(op->getId());
2071 4908 : RA_MERGE(vreg, tied, 0, 0);
2072 :
2073 1636 : if (vreg->getKind() == retKind) {
2074 : tied->setOutPhysId(ret.getRegId());
2075 1636 : tied->flags |= TiedReg::kWReg | TiedReg::kWFunc;
2076 : }
2077 : else {
2078 : // TODO: Function-call return value conversion.
2079 : }
2080 : }
2081 : }
2082 :
2083 : // Init clobbered.
2084 1636 : clobberedRegs.set(X86Reg::kKindGp , Utils::bits(_regCount.getGp()) & (fd.getPassedRegs(X86Reg::kKindGp ) | ~fd.getPreservedRegs(X86Reg::kKindGp )));
2085 1636 : clobberedRegs.set(X86Reg::kKindMm , Utils::bits(_regCount.getMm()) & (fd.getPassedRegs(X86Reg::kKindMm ) | ~fd.getPreservedRegs(X86Reg::kKindMm )));
2086 1636 : clobberedRegs.set(X86Reg::kKindK , Utils::bits(_regCount.getK()) & (fd.getPassedRegs(X86Reg::kKindK ) | ~fd.getPreservedRegs(X86Reg::kKindK )));
2087 1636 : clobberedRegs.set(X86Reg::kKindVec, Utils::bits(_regCount.getVec()) & (fd.getPassedRegs(X86Reg::kKindVec) | ~fd.getPreservedRegs(X86Reg::kKindVec)));
2088 :
2089 6354 : RA_FINALIZE(node_);
2090 : break;
2091 : }
2092 : }
2093 :
2094 : node_ = next;
2095 34686 : } while (node_ != stop);
2096 :
2097 1944 : _Done:
2098 : // Mark exit label and end node as fetched, otherwise they can be removed by
2099 : // `removeUnreachableCode()`, which could lead to a crash in some later step.
2100 : node_ = func->getEnd();
2101 1944 : if (!node_->hasPassData()) {
2102 : CBLabel* fExit = func->getExitNode();
2103 1944 : RA_POPULATE(fExit);
2104 1944 : fExit->setPosition(++position);
2105 :
2106 1944 : RA_POPULATE(node_);
2107 1944 : node_->setPosition(++position);
2108 : }
2109 : return kErrorOk;
2110 :
2111 : // --------------------------------------------------------------------------
2112 : // [Failure]
2113 : // --------------------------------------------------------------------------
2114 :
2115 : NoMem:
2116 : return DebugUtils::errored(kErrorNoHeapMemory);
2117 : }
2118 :
2119 : // ============================================================================
2120 : // [asmjit::X86RAPass - Annotate]
2121 : // ============================================================================
2122 :
2123 0 : Error X86RAPass::annotate() {
2124 : #if !defined(ASMJIT_DISABLE_LOGGING)
2125 : CCFunc* func = getFunc();
2126 :
2127 : CBNode* node_ = func;
2128 : CBNode* end = func->getEnd();
2129 :
2130 0 : Zone& dataZone = cc()->_cbDataZone;
2131 : StringBuilderTmp<256> sb;
2132 :
2133 0 : uint32_t maxLen = 0;
2134 0 : while (node_ && node_ != end) {
2135 0 : if (!node_->hasInlineComment()) {
2136 0 : if (node_->getType() == CBNode::kNodeInst) {
2137 : CBInst* node = static_cast<CBInst*>(node_);
2138 0 : Logging::formatInstruction(
2139 : sb,
2140 : 0,
2141 : cc(),
2142 : cc()->getArchType(),
2143 : node->getInstDetail(), node->getOpArray(), node->getOpCount());
2144 :
2145 : node_->setInlineComment(
2146 0 : static_cast<char*>(dataZone.dup(sb.getData(), sb.getLength(), true)));
2147 0 : maxLen = std::max<uint32_t>(maxLen, static_cast<uint32_t>(sb.getLength()));
2148 :
2149 0 : sb.clear();
2150 : }
2151 : }
2152 :
2153 : node_ = node_->getNext();
2154 : }
2155 0 : _annotationLength = maxLen + 1;
2156 : #endif // !ASMJIT_DISABLE_LOGGING
2157 :
2158 0 : return kErrorOk;
2159 : }
2160 :
2161 : // ============================================================================
2162 : // [asmjit::X86BaseAlloc]
2163 : // ============================================================================
2164 :
2165 : struct X86BaseAlloc {
2166 : // --------------------------------------------------------------------------
2167 : // [Construction / Destruction]
2168 : // --------------------------------------------------------------------------
2169 :
2170 1944 : ASMJIT_INLINE X86BaseAlloc(X86RAPass* context) {
2171 1944 : _context = context;
2172 1944 : _cc = context->cc();
2173 : }
2174 : ASMJIT_INLINE ~X86BaseAlloc() {}
2175 :
2176 : // --------------------------------------------------------------------------
2177 : // [Accessors]
2178 : // --------------------------------------------------------------------------
2179 :
2180 : //! Get the context.
2181 : ASMJIT_INLINE X86RAPass* getContext() const { return _context; }
2182 : //! Get the current state (always the same instance as X86RAPass::_x86State).
2183 10360 : ASMJIT_INLINE X86RAState* getState() const { return _context->getState(); }
2184 :
2185 : //! Get the node.
2186 : ASMJIT_INLINE CBNode* getNode() const { return _node; }
2187 :
2188 : //! Get TiedReg list (all).
2189 : ASMJIT_INLINE TiedReg* getTiedArray() const { return _tiedArray[0]; }
2190 : //! Get TiedReg list (per class).
2191 333328 : ASMJIT_INLINE TiedReg* getTiedArrayByKind(uint32_t kind) const { return _tiedArray[kind]; }
2192 :
2193 : //! Get TiedReg count (all).
2194 : ASMJIT_INLINE uint32_t getTiedCount() const { return _tiedTotal; }
2195 : //! Get TiedReg count (per class).
2196 : ASMJIT_INLINE uint32_t getTiedCountByKind(uint32_t kind) const { return _tiedCount.get(kind); }
2197 :
2198 : //! Get if all variables of the given register `kind` are done.
2199 : ASMJIT_INLINE bool isTiedDone(uint32_t kind) const { return _tiedDone.get(kind) == _tiedCount.get(kind); }
2200 :
2201 : //! Get how many variables have been allocated.
2202 : ASMJIT_INLINE uint32_t getTiedDone(uint32_t kind) const { return _tiedDone.get(kind); }
2203 : //! Add to the count of variables allocated.
2204 26014 : ASMJIT_INLINE void addTiedDone(uint32_t kind, uint32_t n = 1) { _tiedDone.add(kind, n); }
2205 :
2206 : //! Get number of allocable registers per class.
2207 : ASMJIT_INLINE uint32_t getGaRegs(uint32_t kind) const {
2208 : return _context->_gaRegs[kind];
2209 : }
2210 :
2211 : // --------------------------------------------------------------------------
2212 : // [Init / Cleanup]
2213 : // --------------------------------------------------------------------------
2214 :
2215 : protected:
2216 : // Just to prevent calling these methods by X86RAPass::translate().
2217 : ASMJIT_INLINE void init(CBNode* node, X86RAData* map);
2218 : ASMJIT_INLINE void cleanup();
2219 :
2220 : // --------------------------------------------------------------------------
2221 : // [Unuse]
2222 : // --------------------------------------------------------------------------
2223 :
2224 : template<int C>
2225 : ASMJIT_INLINE void unuseBefore();
2226 :
2227 : template<int C>
2228 : ASMJIT_INLINE void unuseAfter();
2229 :
2230 : // --------------------------------------------------------------------------
2231 : // [Members]
2232 : // --------------------------------------------------------------------------
2233 :
2234 : //! RA context.
2235 : X86RAPass* _context;
2236 : //! Compiler.
2237 : X86Compiler* _cc;
2238 :
2239 : //! Node.
2240 : CBNode* _node;
2241 :
2242 : //! Register allocator (RA) data.
2243 : X86RAData* _raData;
2244 : //! TiedReg list (per register kind).
2245 : TiedReg* _tiedArray[Globals::kMaxVRegKinds];
2246 :
2247 : //! Count of all TiedReg's.
2248 : uint32_t _tiedTotal;
2249 :
2250 : //! TiedReg's total counter.
2251 : X86RegCount _tiedCount;
2252 : //! TiedReg's done counter.
2253 : X86RegCount _tiedDone;
2254 : };
2255 :
2256 : // ============================================================================
2257 : // [asmjit::X86BaseAlloc - Init / Cleanup]
2258 : // ============================================================================
2259 :
2260 : ASMJIT_INLINE void X86BaseAlloc::init(CBNode* node, X86RAData* raData) {
2261 36630 : _node = node;
2262 36630 : _raData = raData;
2263 :
2264 : // We have to set the correct cursor in case any instruction is emitted
2265 : // during the allocation phase; it has to be emitted before the current
2266 : // instruction.
2267 36630 : _cc->_setCursor(node->getPrev());
2268 :
2269 : // Setup the lists of variables.
2270 : {
2271 : TiedReg* tied = raData->getTiedArray();
2272 36630 : _tiedArray[X86Reg::kKindGp ] = tied;
2273 36630 : _tiedArray[X86Reg::kKindMm ] = tied + raData->getTiedStart(X86Reg::kKindMm );
2274 36630 : _tiedArray[X86Reg::kKindK ] = tied + raData->getTiedStart(X86Reg::kKindK );
2275 36630 : _tiedArray[X86Reg::kKindVec] = tied + raData->getTiedStart(X86Reg::kKindVec);
2276 : }
2277 :
2278 : // Setup counters.
2279 36630 : _tiedTotal = raData->tiedTotal;
2280 36630 : _tiedCount = raData->tiedCount;
2281 : _tiedDone.reset();
2282 :
2283 : // Connect VREG->TIED.
2284 98004 : for (uint32_t i = 0; i < _tiedTotal; i++) {
2285 61374 : TiedReg* tied = &_tiedArray[0][i];
2286 61374 : VirtReg* vreg = tied->vreg;
2287 61374 : vreg->_tied = tied;
2288 : }
2289 : }
2290 :
2291 : ASMJIT_INLINE void X86BaseAlloc::cleanup() {
2292 : // Disconnect VREG->TIED.
2293 96060 : for (uint32_t i = 0; i < _tiedTotal; i++) {
2294 61374 : TiedReg* tied = &_tiedArray[0][i];
2295 61374 : VirtReg* vreg = tied->vreg;
2296 61374 : vreg->_tied = nullptr;
2297 : }
2298 : }
2299 :
2300 : // ============================================================================
2301 : // [asmjit::X86BaseAlloc - Unuse]
2302 : // ============================================================================
2303 :
2304 : template<int C>
2305 : ASMJIT_INLINE void X86BaseAlloc::unuseBefore() {
2306 : TiedReg* tiedArray = getTiedArrayByKind(C);
2307 : uint32_t tiedCount = getTiedCountByKind(C);
2308 :
2309 : const uint32_t checkFlags = TiedReg::kXReg |
2310 : TiedReg::kRMem |
2311 : TiedReg::kRFunc |
2312 : TiedReg::kRCall ;
2313 :
2314 89706 : for (uint32_t i = 0; i < tiedCount; i++) {
2315 56656 : TiedReg* tied = &tiedArray[i];
2316 56656 : if ((tied->flags & checkFlags) == TiedReg::kWReg)
2317 22104 : _context->unuse<C>(tied->vreg);
2318 : }
2319 : }
2320 :
2321 : template<int C>
2322 : ASMJIT_INLINE void X86BaseAlloc::unuseAfter() {
2323 : TiedReg* tiedArray = getTiedArrayByKind(C);
2324 : uint32_t tiedCount = getTiedCountByKind(C);
2325 :
2326 96060 : for (uint32_t i = 0; i < tiedCount; i++) {
2327 61374 : TiedReg* tied = &tiedArray[i];
2328 61374 : if (tied->flags & TiedReg::kUnuse)
2329 21796 : _context->unuse<C>(tied->vreg);
2330 : }
2331 : }
2332 :
2333 : // ============================================================================
2334 : // [asmjit::X86VarAlloc]
2335 : // ============================================================================
2336 :
2337 : //! \internal
2338 : //!
2339 : //! Register allocator context (asm instructions).
2340 : struct X86VarAlloc : public X86BaseAlloc {
2341 : // --------------------------------------------------------------------------
2342 : // [Construction / Destruction]
2343 : // --------------------------------------------------------------------------
2344 :
2345 1944 : ASMJIT_INLINE X86VarAlloc(X86RAPass* context) : X86BaseAlloc(context) {}
2346 1944 : ASMJIT_INLINE ~X86VarAlloc() {}
2347 :
2348 : // --------------------------------------------------------------------------
2349 : // [Run]
2350 : // --------------------------------------------------------------------------
2351 :
2352 : Error run(CBNode* node);
2353 :
2354 : // --------------------------------------------------------------------------
2355 : // [Init / Cleanup]
2356 : // --------------------------------------------------------------------------
2357 :
2358 : protected:
2359 : // Just to prevent calling these methods by X86RAPass::translate().
2360 : ASMJIT_INLINE void init(CBNode* node, X86RAData* map);
2361 : ASMJIT_INLINE void cleanup();
2362 :
2363 : // --------------------------------------------------------------------------
2364 : // [Plan / Spill / Alloc]
2365 : // --------------------------------------------------------------------------
2366 :
2367 : template<int C>
2368 : ASMJIT_INLINE void plan();
2369 :
2370 : template<int C>
2371 : ASMJIT_INLINE void spill();
2372 :
2373 : template<int C>
2374 : ASMJIT_INLINE void alloc();
2375 :
2376 : // --------------------------------------------------------------------------
2377 : // [GuessAlloc / GuessSpill]
2378 : // --------------------------------------------------------------------------
2379 :
2380 : //! Guess which register is the best candidate for `vreg` from `allocableRegs`.
2381 : //!
2382 : //! The guess is based on looking ahead and inspecting register allocator
2383 : //! instructions. The main reason is to prevent allocation to a register
2384 : //! which is needed by next instruction(s). The guess look tries to go as far
2385 : //! as possible, after the remaining registers are zero, the mask of previous
2386 : //! registers (called 'safeRegs') is returned.
2387 : template<int C>
2388 : ASMJIT_INLINE uint32_t guessAlloc(VirtReg* vreg, uint32_t allocableRegs);
2389 :
2390 : //! Guess whether to move the given `vreg` instead of spill.
2391 : template<int C>
2392 : ASMJIT_INLINE uint32_t guessSpill(VirtReg* vreg, uint32_t allocableRegs);
2393 :
2394 : // --------------------------------------------------------------------------
2395 : // [Modified]
2396 : // --------------------------------------------------------------------------
2397 :
2398 : template<int C>
2399 : ASMJIT_INLINE void modified();
2400 :
2401 : // --------------------------------------------------------------------------
2402 : // [Members]
2403 : // --------------------------------------------------------------------------
2404 :
2405 : //! Will alloc to these registers.
2406 : X86RegMask _willAlloc;
2407 : //! Will spill these registers.
2408 : X86RegMask _willSpill;
2409 : };
2410 :
2411 : // ============================================================================
2412 : // [asmjit::X86VarAlloc - Run]
2413 : // ============================================================================
2414 :
2415 34994 : Error X86VarAlloc::run(CBNode* node_) {
2416 : // Initialize.
2417 : X86RAData* raData = node_->getPassData<X86RAData>();
2418 : // Initialize the allocator; connect Vd->Va.
2419 : init(node_, raData);
2420 :
2421 34994 : if (raData->tiedTotal != 0) {
2422 : // Unuse overwritten variables.
2423 : unuseBefore<X86Reg::kKindGp>();
2424 : unuseBefore<X86Reg::kKindMm>();
2425 : unuseBefore<X86Reg::kKindVec>();
2426 :
2427 : // Plan the allocation. Planner assigns input/output registers for each
2428 : // variable and decides whether to allocate it in register or stack.
2429 : plan<X86Reg::kKindGp>();
2430 : plan<X86Reg::kKindMm>();
2431 : plan<X86Reg::kKindVec>();
2432 :
2433 : // Spill all variables marked by plan().
2434 : spill<X86Reg::kKindGp>();
2435 : spill<X86Reg::kKindMm>();
2436 : spill<X86Reg::kKindVec>();
2437 :
2438 : // Alloc all variables marked by plan().
2439 : alloc<X86Reg::kKindGp>();
2440 : alloc<X86Reg::kKindMm>();
2441 : alloc<X86Reg::kKindVec>();
2442 :
2443 : // Translate node operands.
2444 33050 : if (node_->getType() == CBNode::kNodeInst) {
2445 : CBInst* node = static_cast<CBInst*>(node_);
2446 31106 : if (node->hasExtraReg()) {
2447 : Reg reg = node->getExtraReg().toReg<Reg>();
2448 0 : ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, ®, 1));
2449 : node->setExtraReg(reg);
2450 : }
2451 31106 : ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount()));
2452 : }
2453 1944 : else if (node_->getType() == CBNode::kNodePushArg) {
2454 : CCPushArg* node = static_cast<CCPushArg*>(node_);
2455 :
2456 : CCFuncCall* call = static_cast<CCFuncCall*>(node->getCall());
2457 : FuncDetail& fd = call->getDetail();
2458 :
2459 : uint32_t argIndex = 0;
2460 0 : uint32_t argMask = node->_args;
2461 :
2462 : VirtReg* cvtReg = node->getCvtReg();
2463 : VirtReg* srcReg = node->getSrcReg();
2464 :
2465 : // Convert first.
2466 : ASMJIT_ASSERT(srcReg->getPhysId() != Globals::kInvalidRegId);
2467 :
2468 0 : if (cvtReg) {
2469 : ASMJIT_ASSERT(cvtReg->getPhysId() != Globals::kInvalidRegId);
2470 :
2471 : X86Reg dstOp(X86Reg::fromSignature(cvtReg->getSignature(), cvtReg->getId()));
2472 : X86Reg srcOp(X86Reg::fromSignature(srcReg->getSignature(), srcReg->getId()));
2473 :
2474 : // Emit conversion after the prolog.
2475 0 : X86Internal::emitArgMove(reinterpret_cast<X86Emitter*>(_context->cc()),
2476 : dstOp, cvtReg->getTypeId(),
2477 0 : srcOp, srcReg->getTypeId(), _context->_avxEnabled);
2478 : srcReg = cvtReg;
2479 : }
2480 :
2481 0 : while (argMask != 0) {
2482 0 : if (argMask & 0x1) {
2483 0 : FuncDetail::Value& arg = fd.getArg(argIndex);
2484 : ASMJIT_ASSERT(arg.byStack());
2485 :
2486 0 : X86Mem dst = x86::ptr(_context->_zsp, -static_cast<int>(_context->getGpSize()) + arg.getStackOffset());
2487 0 : _context->emitRegToStack(arg.getTypeId(), &dst, srcReg->getTypeId(), srcReg->getPhysId());
2488 : }
2489 :
2490 0 : argIndex++;
2491 0 : argMask >>= 1;
2492 : }
2493 : }
2494 :
2495 : // Mark variables as modified.
2496 : modified<X86Reg::kKindGp>();
2497 : modified<X86Reg::kKindMm>();
2498 : modified<X86Reg::kKindVec>();
2499 :
2500 : // Cleanup; disconnect Vd->Va.
2501 : cleanup();
2502 :
2503 : // Update clobbered mask.
2504 33050 : _context->_clobberedRegs.or_(_willAlloc);
2505 : }
2506 :
2507 : // Update clobbered mask.
2508 34994 : _context->_clobberedRegs.or_(raData->clobberedRegs);
2509 :
2510 : // Unuse.
2511 34994 : if (raData->tiedTotal != 0) {
2512 : unuseAfter<X86Reg::kKindGp>();
2513 : unuseAfter<X86Reg::kKindMm>();
2514 : unuseAfter<X86Reg::kKindVec>();
2515 : }
2516 :
2517 : return kErrorOk;
2518 : }
2519 :
2520 : // ============================================================================
2521 : // [asmjit::X86VarAlloc - Init / Cleanup]
2522 : // ============================================================================
2523 :
2524 : ASMJIT_INLINE void X86VarAlloc::init(CBNode* node, X86RAData* raData) {
2525 : X86BaseAlloc::init(node, raData);
2526 :
2527 : // These will block planner from assigning them during planning. Planner will
2528 : // add more registers when assigning registers to variables that don't need
2529 : // any specific register.
2530 34994 : _willAlloc = raData->inRegs;
2531 : _willAlloc.or_(raData->outRegs);
2532 : _willSpill.reset();
2533 : }
2534 :
2535 : ASMJIT_INLINE void X86VarAlloc::cleanup() {
2536 : X86BaseAlloc::cleanup();
2537 : }
2538 :
2539 : // ============================================================================
2540 : // [asmjit::X86VarAlloc - Plan / Spill / Alloc]
2541 : // ============================================================================
2542 :
2543 : template<int C>
2544 : ASMJIT_INLINE void X86VarAlloc::plan() {
2545 46366 : if (isTiedDone(C)) return;
2546 :
2547 : uint32_t i;
2548 : uint32_t willAlloc = _willAlloc.get(C);
2549 : uint32_t willFree = 0;
2550 :
2551 : TiedReg* tiedArray = getTiedArrayByKind(C);
2552 : uint32_t tiedCount = getTiedCountByKind(C);
2553 : X86RAState* state = getState();
2554 :
2555 : // Calculate 'willAlloc' and 'willFree' masks based on mandatory masks.
2556 95774 : for (i = 0; i < tiedCount; i++) {
2557 56656 : TiedReg* tied = &tiedArray[i];
2558 56656 : VirtReg* vreg = tied->vreg;
2559 :
2560 56656 : uint32_t vaFlags = tied->flags;
2561 : uint32_t physId = vreg->getPhysId();
2562 56656 : uint32_t regMask = (physId != Globals::kInvalidRegId) ? Utils::mask(physId) : 0;
2563 :
2564 56656 : if ((vaFlags & TiedReg::kXReg) != 0) {
2565 : // Planning register allocation. First check whether the variable is
2566 : // already allocated in register and if it can stay allocated there.
2567 : //
2568 : // The following conditions may happen:
2569 : //
2570 : // a) Allocated register is one of the mandatoryRegs.
2571 : // b) Allocated register is one of the allocableRegs.
2572 56656 : uint32_t mandatoryRegs = tied->inRegs;
2573 56656 : uint32_t allocableRegs = tied->allocableRegs;
2574 :
2575 56656 : if (regMask != 0) {
2576 : // Special path for planning output-only registers.
2577 30614 : if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
2578 0 : uint32_t outPhysId = tied->outPhysId;
2579 0 : mandatoryRegs = (outPhysId != Globals::kInvalidRegId) ? Utils::mask(outPhysId) : 0;
2580 :
2581 0 : if ((mandatoryRegs | allocableRegs) & regMask) {
2582 : tied->setOutPhysId(physId);
2583 0 : tied->flags |= TiedReg::kWDone;
2584 :
2585 0 : if (mandatoryRegs & regMask) {
2586 : // Case 'a' - 'willAlloc' contains initially all inRegs from all TiedReg's.
2587 : ASMJIT_ASSERT((willAlloc & regMask) != 0);
2588 : }
2589 : else {
2590 : // Case 'b'.
2591 : tied->setOutPhysId(physId);
2592 0 : willAlloc |= regMask;
2593 : }
2594 :
2595 : addTiedDone(C);
2596 0 : continue;
2597 : }
2598 : }
2599 : else {
2600 30614 : if ((mandatoryRegs | allocableRegs) & regMask) {
2601 : tied->setInPhysId(physId);
2602 30280 : tied->flags |= TiedReg::kRDone;
2603 :
2604 30280 : if (mandatoryRegs & regMask) {
2605 : // Case 'a' - 'willAlloc' contains initially all inRegs from all TiedReg's.
2606 : ASMJIT_ASSERT((willAlloc & regMask) != 0);
2607 : }
2608 : else {
2609 : // Case 'b'.
2610 28670 : tied->inRegs |= regMask;
2611 28670 : willAlloc |= regMask;
2612 : }
2613 :
2614 : addTiedDone(C);
2615 30280 : continue;
2616 : }
2617 : }
2618 : }
2619 :
2620 : // Variable is not allocated or allocated in register that doesn't
2621 : // match inRegs or allocableRegs. The next step is to pick the best
2622 : // register for this variable. If `inRegs` contains any register the
2623 : // decision is simple - we have to follow, in other case will use
2624 : // the advantage of `guessAlloc()` to find a register (or registers)
2625 : // by looking ahead. But the best way to find a good register is not
2626 : // here since now we have no information about the registers that
2627 : // will be freed. So instead of finding register here, we just mark
2628 : // the current register (if variable is allocated) as `willFree` so
2629 : // the planner can use this information in the second step to plan the
2630 : // allocation as a whole.
2631 26376 : willFree |= regMask;
2632 26376 : continue;
2633 26376 : }
2634 : else {
2635 0 : if (regMask != 0) {
2636 0 : willFree |= regMask;
2637 0 : continue;
2638 : }
2639 : else {
2640 0 : tied->flags |= TiedReg::kRDone;
2641 : addTiedDone(C);
2642 0 : continue;
2643 : }
2644 : }
2645 : }
2646 :
2647 : // Occupied registers without 'willFree' registers; contains basically
2648 : // all the registers we can use to allocate variables without inRegs
2649 : // specified.
2650 39118 : uint32_t occupied = state->_occupied.get(C) & ~willFree;
2651 : uint32_t willSpill = 0;
2652 :
2653 : // Find the best registers for variables that are not allocated yet.
2654 95774 : for (i = 0; i < tiedCount; i++) {
2655 56656 : TiedReg* tied = &tiedArray[i];
2656 56656 : VirtReg* vreg = tied->vreg;
2657 56656 : uint32_t vaFlags = tied->flags;
2658 :
2659 56656 : if ((vaFlags & TiedReg::kXReg) != 0) {
2660 56656 : if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
2661 22104 : if (vaFlags & TiedReg::kWDone)
2662 0 : continue;
2663 :
2664 : // Skip all registers that have assigned outPhysId. Spill if occupied.
2665 22104 : if (tied->hasOutPhysId()) {
2666 0 : uint32_t outRegs = Utils::mask(tied->outPhysId);
2667 0 : willSpill |= occupied & outRegs;
2668 0 : continue;
2669 0 : }
2670 : }
2671 : else {
2672 34552 : if (vaFlags & TiedReg::kRDone)
2673 30280 : continue;
2674 :
2675 : // We skip all registers that have assigned inPhysId, indicates that
2676 : // the register to allocate in is known.
2677 4272 : if (tied->hasInPhysId()) {
2678 0 : uint32_t inRegs = tied->inRegs;
2679 0 : willSpill |= occupied & inRegs;
2680 0 : continue;
2681 0 : }
2682 : }
2683 :
2684 26376 : uint32_t m = tied->inRegs;
2685 26376 : if (tied->hasOutPhysId())
2686 0 : m |= Utils::mask(tied->outPhysId);
2687 :
2688 26376 : m = tied->allocableRegs & ~(willAlloc ^ m);
2689 : m = guessAlloc<C>(vreg, m);
2690 : ASMJIT_ASSERT(m != 0);
2691 :
2692 26376 : uint32_t candidateRegs = m & ~occupied;
2693 : uint32_t homeMask = vreg->getHomeMask();
2694 :
2695 : uint32_t physId;
2696 : uint32_t regMask;
2697 :
2698 26376 : if (candidateRegs == 0) {
2699 138 : candidateRegs = m & occupied & ~state->_modified.get(C);
2700 138 : if (candidateRegs == 0)
2701 : candidateRegs = m;
2702 : }
2703 26376 : if (candidateRegs & homeMask) candidateRegs &= homeMask;
2704 :
2705 : physId = Utils::findFirstBit(candidateRegs);
2706 : regMask = Utils::mask(physId);
2707 :
2708 26376 : if ((vaFlags & TiedReg::kXReg) == TiedReg::kWReg) {
2709 : tied->setOutPhysId(physId);
2710 : }
2711 : else {
2712 : tied->setInPhysId(physId);
2713 4272 : tied->inRegs = regMask;
2714 : }
2715 :
2716 26376 : willAlloc |= regMask;
2717 26376 : willSpill |= regMask & occupied;
2718 : willFree &=~regMask;
2719 26376 : occupied |= regMask;
2720 :
2721 26376 : continue;
2722 26376 : }
2723 0 : else if ((vaFlags & TiedReg::kXMem) != 0) {
2724 : uint32_t physId = vreg->getPhysId();
2725 0 : if (physId != Globals::kInvalidRegId && (vaFlags & TiedReg::kXMem) != TiedReg::kWMem) {
2726 0 : willSpill |= Utils::mask(physId);
2727 : }
2728 : }
2729 : }
2730 :
2731 : // Set calculated masks back to the allocator; needed by spill() and alloc().
2732 : _willSpill.set(C, willSpill);
2733 : _willAlloc.set(C, willAlloc);
2734 : }
2735 :
2736 : template<int C>
2737 : ASMJIT_INLINE void X86VarAlloc::spill() {
2738 : uint32_t m = _willSpill.get(C);
2739 : uint32_t i = static_cast<uint32_t>(0) - 1;
2740 33050 : if (m == 0) return;
2741 :
2742 : X86RAState* state = getState();
2743 : VirtReg** vregs = state->getListByKind(C);
2744 :
2745 : // Available registers for decision if move has any benefit over spill.
2746 : uint32_t availableRegs = getGaRegs(C) & ~(state->_occupied.get(C) | m | _willAlloc.get(C));
2747 :
2748 : do {
2749 : // We always advance one more to destroy the bit that we have found.
2750 138 : uint32_t bitIndex = Utils::findFirstBit(m) + 1;
2751 :
2752 138 : i += bitIndex;
2753 138 : m >>= bitIndex;
2754 :
2755 138 : VirtReg* vreg = vregs[i];
2756 : ASMJIT_ASSERT(vreg);
2757 :
2758 : TiedReg* tied = vreg->_tied;
2759 : ASMJIT_ASSERT(!tied || (tied->flags & TiedReg::kXReg) == 0);
2760 :
2761 : if (vreg->isModified() && availableRegs) {
2762 : // Don't check for alternatives if the variable has to be spilled.
2763 : if (!tied || (tied->flags & TiedReg::kSpill) == 0) {
2764 : uint32_t altRegs = guessSpill<C>(vreg, availableRegs);
2765 :
2766 : if (altRegs != 0) {
2767 : uint32_t physId = Utils::findFirstBit(altRegs);
2768 : uint32_t regMask = Utils::mask(physId);
2769 :
2770 : _context->move<C>(vreg, physId);
2771 : availableRegs ^= regMask;
2772 : continue;
2773 : }
2774 : }
2775 : }
2776 :
2777 138 : _context->spill<C>(vreg);
2778 138 : } while (m != 0);
2779 : }
2780 :
2781 : template<int C>
2782 : ASMJIT_INLINE void X86VarAlloc::alloc() {
2783 40298 : if (isTiedDone(C)) return;
2784 :
2785 : uint32_t i;
2786 : bool didWork;
2787 :
2788 : TiedReg* tiedArray = getTiedArrayByKind(C);
2789 : uint32_t tiedCount = getTiedCountByKind(C);
2790 :
2791 : // Alloc `in` regs.
2792 29526 : do {
2793 : didWork = false;
2794 74516 : for (i = 0; i < tiedCount; i++) {
2795 44990 : TiedReg* aTied = &tiedArray[i];
2796 44990 : VirtReg* aVReg = aTied->vreg;
2797 :
2798 44990 : if ((aTied->flags & (TiedReg::kRReg | TiedReg::kRDone)) != TiedReg::kRReg)
2799 40718 : continue;
2800 :
2801 : uint32_t aPhysId = aVReg->getPhysId();
2802 4272 : uint32_t bPhysId = aTied->inPhysId;
2803 :
2804 : // Shouldn't be the same.
2805 : ASMJIT_ASSERT(aPhysId != bPhysId);
2806 :
2807 4272 : VirtReg* bVReg = getState()->getListByKind(C)[bPhysId];
2808 4272 : if (bVReg) {
2809 : // Gp registers only - Swap two registers if we can solve two
2810 : // allocation tasks by a single 'xchg' instruction, swapping
2811 : // two registers required by the instruction/node or one register
2812 : // required with another non-required.
2813 0 : if (C == X86Reg::kKindGp && aPhysId != Globals::kInvalidRegId) {
2814 0 : TiedReg* bTied = bVReg->_tied;
2815 : _context->swapGp(aVReg, bVReg);
2816 :
2817 0 : aTied->flags |= TiedReg::kRDone;
2818 : addTiedDone(C);
2819 :
2820 : // Double-hit, two registers allocated by a single xchg.
2821 0 : if (bTied && bTied->inPhysId == aPhysId) {
2822 0 : bTied->flags |= TiedReg::kRDone;
2823 : addTiedDone(C);
2824 : }
2825 :
2826 : didWork = true;
2827 0 : continue;
2828 0 : }
2829 : }
2830 4272 : else if (aPhysId != Globals::kInvalidRegId) {
2831 : _context->move<C>(aVReg, bPhysId);
2832 :
2833 334 : aTied->flags |= TiedReg::kRDone;
2834 : addTiedDone(C);
2835 :
2836 : didWork = true;
2837 334 : continue;
2838 : }
2839 : else {
2840 : _context->alloc<C>(aVReg, bPhysId);
2841 :
2842 3938 : aTied->flags |= TiedReg::kRDone;
2843 : addTiedDone(C);
2844 :
2845 : didWork = true;
2846 3938 : continue;
2847 : }
2848 : }
2849 : } while (didWork);
2850 :
2851 : // Alloc 'out' regs.
2852 62068 : for (i = 0; i < tiedCount; i++) {
2853 36814 : TiedReg* tied = &tiedArray[i];
2854 36814 : VirtReg* vreg = tied->vreg;
2855 :
2856 36814 : if ((tied->flags & (TiedReg::kXReg | TiedReg::kWDone)) != TiedReg::kWReg)
2857 14710 : continue;
2858 :
2859 22104 : uint32_t physId = tied->outPhysId;
2860 : ASMJIT_ASSERT(physId != Globals::kInvalidRegId);
2861 :
2862 22104 : if (vreg->getPhysId() != physId) {
2863 : ASMJIT_ASSERT(getState()->getListByKind(C)[physId] == nullptr);
2864 22104 : _context->attach<C>(vreg, physId, false);
2865 : }
2866 :
2867 22104 : tied->flags |= TiedReg::kWDone;
2868 : addTiedDone(C);
2869 : }
2870 : }
2871 :
2872 : // ============================================================================
2873 : // [asmjit::X86VarAlloc - GuessAlloc / GuessSpill]
2874 : // ============================================================================
2875 :
2876 : template<int C>
2877 : ASMJIT_INLINE uint32_t X86VarAlloc::guessAlloc(VirtReg* vreg, uint32_t allocableRegs) {
2878 : ASMJIT_ASSERT(allocableRegs != 0);
2879 :
2880 : // Stop now if there is only one bit (register) set in `allocableRegs` mask.
2881 : if (Utils::isPowerOf2(allocableRegs)) return allocableRegs;
2882 :
2883 26042 : uint32_t raId = vreg->_raId;
2884 : uint32_t safeRegs = allocableRegs;
2885 :
2886 : uint32_t i;
2887 : uint32_t maxLookAhead = kCompilerDefaultLookAhead;
2888 :
2889 : // Look ahead and calculate mask of special registers on both - input/output.
2890 26042 : CBNode* node = _node;
2891 118938 : for (i = 0; i < maxLookAhead; i++) {
2892 : X86RAData* raData = node->getPassData<X86RAData>();
2893 118866 : RABits* liveness = raData ? raData->liveness : static_cast<RABits*>(nullptr);
2894 :
2895 : // If the variable becomes dead it doesn't make sense to continue.
2896 118866 : if (liveness && !liveness->getBit(raId)) break;
2897 :
2898 : // Stop on `CBSentinel` and `CCFuncRet`.
2899 99048 : if (node->hasFlag(CBNode::kFlagIsRet)) break;
2900 :
2901 : // Stop on conditional jump, we don't follow them.
2902 99048 : if (node->hasFlag(CBNode::kFlagIsJcc)) break;
2903 :
2904 : // Advance on non-conditional jump.
2905 99048 : if (node->hasFlag(CBNode::kFlagIsJmp)) {
2906 : node = static_cast<CBJump*>(node)->getTarget();
2907 : // Stop on jump that is not followed.
2908 0 : if (!node) break;
2909 : }
2910 :
2911 : node = node->getNext();
2912 : ASMJIT_ASSERT(node != nullptr);
2913 :
2914 : raData = node->getPassData<X86RAData>();
2915 99048 : if (raData) {
2916 : TiedReg* tied = raData->findTiedByKind(C, vreg);
2917 : uint32_t mask;
2918 :
2919 99048 : if (tied) {
2920 : // If the variable is overwritten it doesn't make sense to continue.
2921 29868 : if ((tied->flags & TiedReg::kRAll) == 0)
2922 : break;
2923 :
2924 29868 : mask = tied->allocableRegs;
2925 29868 : if (mask != 0) {
2926 29868 : allocableRegs &= mask;
2927 29868 : if (allocableRegs == 0) break;
2928 : safeRegs = allocableRegs;
2929 : }
2930 :
2931 29212 : mask = tied->inRegs;
2932 29212 : if (mask != 0) {
2933 2092 : allocableRegs &= mask;
2934 2092 : if (allocableRegs == 0) break;
2935 : safeRegs = allocableRegs;
2936 2092 : break;
2937 : }
2938 :
2939 27120 : allocableRegs &= ~(raData->outRegs.get(C) | raData->clobberedRegs.get(C));
2940 27120 : if (allocableRegs == 0) break;
2941 : }
2942 : else {
2943 69180 : allocableRegs &= ~(raData->inRegs.get(C) | raData->outRegs.get(C) | raData->clobberedRegs.get(C));
2944 69180 : if (allocableRegs == 0) break;
2945 : }
2946 :
2947 : safeRegs = allocableRegs;
2948 : }
2949 : }
2950 :
2951 : return safeRegs;
2952 : }
2953 :
2954 : template<int C>
2955 : ASMJIT_INLINE uint32_t X86VarAlloc::guessSpill(VirtReg* vreg, uint32_t allocableRegs) {
2956 : ASMJIT_ASSERT(allocableRegs != 0);
2957 :
2958 : return 0;
2959 : }
2960 :
2961 : // ============================================================================
2962 : // [asmjit::X86VarAlloc - Modified]
2963 : // ============================================================================
2964 :
2965 : template<int C>
2966 : ASMJIT_INLINE void X86VarAlloc::modified() {
2967 : TiedReg* tiedArray = getTiedArrayByKind(C);
2968 : uint32_t tiedCount = getTiedCountByKind(C);
2969 :
2970 89706 : for (uint32_t i = 0; i < tiedCount; i++) {
2971 56656 : TiedReg* tied = &tiedArray[i];
2972 :
2973 56656 : if (tied->flags & TiedReg::kWReg) {
2974 30864 : VirtReg* vreg = tied->vreg;
2975 :
2976 : uint32_t physId = vreg->getPhysId();
2977 : uint32_t regMask = Utils::mask(physId);
2978 :
2979 : vreg->setModified(true);
2980 30864 : _context->_x86State._modified.or_(C, regMask);
2981 : }
2982 : }
2983 : }
2984 :
2985 : // ============================================================================
2986 : // [asmjit::X86CallAlloc]
2987 : // ============================================================================
2988 :
2989 : //! \internal
2990 : //!
2991 : //! Register allocator context (function call).
2992 : struct X86CallAlloc : public X86BaseAlloc {
2993 : // --------------------------------------------------------------------------
2994 : // [Construction / Destruction]
2995 : // --------------------------------------------------------------------------
2996 :
2997 1944 : ASMJIT_INLINE X86CallAlloc(X86RAPass* context) : X86BaseAlloc(context) {}
2998 1944 : ASMJIT_INLINE ~X86CallAlloc() {}
2999 :
3000 : // --------------------------------------------------------------------------
3001 : // [Accessors]
3002 : // --------------------------------------------------------------------------
3003 :
3004 : //! Get the node.
3005 1636 : ASMJIT_INLINE CCFuncCall* getNode() const { return static_cast<CCFuncCall*>(_node); }
3006 :
3007 : // --------------------------------------------------------------------------
3008 : // [Run]
3009 : // --------------------------------------------------------------------------
3010 :
3011 : Error run(CCFuncCall* node);
3012 :
3013 : // --------------------------------------------------------------------------
3014 : // [Init / Cleanup]
3015 : // --------------------------------------------------------------------------
3016 :
3017 : protected:
3018 : // Just to prevent calling these methods from X86RAPass::translate().
3019 : ASMJIT_INLINE void init(CCFuncCall* node, X86RAData* raData);
3020 : ASMJIT_INLINE void cleanup();
3021 :
3022 : // --------------------------------------------------------------------------
3023 : // [Plan / Alloc / Spill / Move]
3024 : // --------------------------------------------------------------------------
3025 :
3026 : template<int C>
3027 : ASMJIT_INLINE void plan();
3028 :
3029 : template<int C>
3030 : ASMJIT_INLINE void spill();
3031 :
3032 : template<int C>
3033 : ASMJIT_INLINE void alloc();
3034 :
3035 : // --------------------------------------------------------------------------
3036 : // [AllocImmsOnStack]
3037 : // --------------------------------------------------------------------------
3038 :
3039 : ASMJIT_INLINE void allocImmsOnStack();
3040 :
3041 : // --------------------------------------------------------------------------
3042 : // [Duplicate]
3043 : // --------------------------------------------------------------------------
3044 :
3045 : template<int C>
3046 : ASMJIT_INLINE void duplicate();
3047 :
3048 : // --------------------------------------------------------------------------
3049 : // [GuessAlloc / GuessSpill]
3050 : // --------------------------------------------------------------------------
3051 :
3052 : template<int C>
3053 : ASMJIT_INLINE uint32_t guessAlloc(VirtReg* vreg, uint32_t allocableRegs);
3054 :
3055 : template<int C>
3056 : ASMJIT_INLINE uint32_t guessSpill(VirtReg* vreg, uint32_t allocableRegs);
3057 :
3058 : // --------------------------------------------------------------------------
3059 : // [Save]
3060 : // --------------------------------------------------------------------------
3061 :
3062 : template<int C>
3063 : ASMJIT_INLINE void save();
3064 :
3065 : // --------------------------------------------------------------------------
3066 : // [Clobber]
3067 : // --------------------------------------------------------------------------
3068 :
3069 : template<int C>
3070 : ASMJIT_INLINE void clobber();
3071 :
3072 : // --------------------------------------------------------------------------
3073 : // [Ret]
3074 : // --------------------------------------------------------------------------
3075 :
3076 : ASMJIT_INLINE void ret();
3077 :
3078 : // --------------------------------------------------------------------------
3079 : // [Members]
3080 : // --------------------------------------------------------------------------
3081 :
3082 : //! Will alloc to these registers.
3083 : X86RegMask _willAlloc;
3084 : //! Will spill these registers.
3085 : X86RegMask _willSpill;
3086 : };
3087 :
3088 : // ============================================================================
3089 : // [asmjit::X86CallAlloc - Run]
3090 : // ============================================================================
3091 :
3092 1636 : Error X86CallAlloc::run(CCFuncCall* node) {
3093 : // Initialize the allocator; prepare basics and connect Vd->Va.
3094 : X86RAData* raData = node->getPassData<X86RAData>();
3095 : init(node, raData);
3096 :
3097 : // Plan register allocation. Planner is only able to assign one register per
3098 : // variable. If any variable is used multiple times it will be handled later.
3099 : plan<X86Reg::kKindGp >();
3100 : plan<X86Reg::kKindMm >();
3101 : plan<X86Reg::kKindVec>();
3102 :
3103 : // Spill.
3104 : spill<X86Reg::kKindGp >();
3105 : spill<X86Reg::kKindMm >();
3106 : spill<X86Reg::kKindVec>();
3107 :
3108 : // Alloc.
3109 : alloc<X86Reg::kKindGp >();
3110 : alloc<X86Reg::kKindMm >();
3111 : alloc<X86Reg::kKindVec>();
3112 :
3113 : // Unuse clobbered registers that are not used to pass function arguments and
3114 : // save variables used to pass function arguments that will be reused later on.
3115 : save<X86Reg::kKindGp >();
3116 : save<X86Reg::kKindMm >();
3117 : save<X86Reg::kKindVec>();
3118 :
3119 : // Allocate immediates in registers and on the stack.
3120 : allocImmsOnStack();
3121 :
3122 : // Duplicate.
3123 : duplicate<X86Reg::kKindGp >();
3124 : duplicate<X86Reg::kKindMm >();
3125 : duplicate<X86Reg::kKindVec>();
3126 :
3127 : // Translate call operand.
3128 1636 : ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount()));
3129 :
3130 : // To emit instructions after call.
3131 1636 : _cc->_setCursor(node);
3132 :
3133 : // If the callee pops stack it has to be manually adjusted back.
3134 : FuncDetail& fd = node->getDetail();
3135 1636 : if (fd.hasFlag(CallConv::kFlagCalleePopsStack) && fd.getArgStackSize() != 0)
3136 0 : _cc->emit(X86Inst::kIdSub, _context->_zsp, static_cast<int>(fd.getArgStackSize()));
3137 :
3138 : // Clobber.
3139 : clobber<X86Reg::kKindGp >();
3140 : clobber<X86Reg::kKindMm >();
3141 : clobber<X86Reg::kKindVec>();
3142 :
3143 : // Return.
3144 : ret();
3145 :
3146 : // Unuse.
3147 : unuseAfter<X86Reg::kKindGp >();
3148 : unuseAfter<X86Reg::kKindMm >();
3149 : unuseAfter<X86Reg::kKindVec>();
3150 :
3151 : // Cleanup; disconnect Vd->Va.
3152 : cleanup();
3153 :
3154 : return kErrorOk;
3155 : }
3156 :
3157 : // ============================================================================
3158 : // [asmjit::X86CallAlloc - Init / Cleanup]
3159 : // ============================================================================
3160 :
3161 : ASMJIT_INLINE void X86CallAlloc::init(CCFuncCall* node, X86RAData* raData) {
3162 : X86BaseAlloc::init(node, raData);
3163 :
3164 : // Create mask of all registers that will be used to pass function arguments.
3165 : _willAlloc.reset();
3166 : _willAlloc.set(X86Reg::kKindGp , node->getDetail().getUsedRegs(X86Reg::kKindGp ));
3167 : _willAlloc.set(X86Reg::kKindMm , node->getDetail().getUsedRegs(X86Reg::kKindMm ));
3168 : _willAlloc.set(X86Reg::kKindK , node->getDetail().getUsedRegs(X86Reg::kKindK ));
3169 : _willAlloc.set(X86Reg::kKindVec, node->getDetail().getUsedRegs(X86Reg::kKindVec));
3170 : _willSpill.reset();
3171 : }
3172 :
3173 : ASMJIT_INLINE void X86CallAlloc::cleanup() {
3174 : X86BaseAlloc::cleanup();
3175 : }
3176 :
3177 : // ============================================================================
3178 : // [asmjit::X86CallAlloc - Plan / Spill / Alloc]
3179 : // ============================================================================
3180 :
3181 : template<int C>
3182 : ASMJIT_INLINE void X86CallAlloc::plan() {
3183 : uint32_t i;
3184 4908 : uint32_t clobbered = _raData->clobberedRegs.get(C);
3185 :
3186 : uint32_t willAlloc = _willAlloc.get(C);
3187 4908 : uint32_t willFree = clobbered & ~willAlloc;
3188 :
3189 : TiedReg* tiedArray = getTiedArrayByKind(C);
3190 : uint32_t tiedCount = getTiedCountByKind(C);
3191 :
3192 : X86RAState* state = getState();
3193 :
3194 : // Calculate 'willAlloc' and 'willFree' masks based on mandatory masks.
3195 9626 : for (i = 0; i < tiedCount; i++) {
3196 4718 : TiedReg* tied = &tiedArray[i];
3197 4718 : VirtReg* vreg = tied->vreg;
3198 :
3199 4718 : uint32_t vaFlags = tied->flags;
3200 : uint32_t physId = vreg->getPhysId();
3201 4718 : uint32_t regMask = (physId != Globals::kInvalidRegId) ? Utils::mask(physId) : 0;
3202 :
3203 4718 : if ((vaFlags & TiedReg::kRReg) != 0) {
3204 : // Planning register allocation. First check whether the variable is
3205 : // already allocated in register and if it can stay there. Function
3206 : // arguments are passed either in a specific register or in stack so
3207 : // we care mostly of mandatory registers.
3208 3082 : uint32_t inRegs = tied->inRegs;
3209 :
3210 3082 : if (inRegs == 0) {
3211 1636 : inRegs = tied->allocableRegs;
3212 : }
3213 :
3214 : // Optimize situation where the variable has to be allocated in a
3215 : // mandatory register, but it's already allocated in register that
3216 : // is not clobbered (i.e. it will survive function call).
3217 3082 : if ((regMask & inRegs) != 0 || ((regMask & ~clobbered) != 0 && (vaFlags & TiedReg::kUnuse) == 0)) {
3218 : tied->setInPhysId(physId);
3219 2274 : tied->flags |= TiedReg::kRDone;
3220 : addTiedDone(C);
3221 : }
3222 : else {
3223 808 : willFree |= regMask;
3224 : }
3225 : }
3226 : else {
3227 : // Memory access - if variable is allocated it has to be freed.
3228 1636 : if (regMask != 0) {
3229 0 : willFree |= regMask;
3230 : }
3231 : else {
3232 1636 : tied->flags |= TiedReg::kRDone;
3233 : addTiedDone(C);
3234 : }
3235 : }
3236 : }
3237 :
3238 : // Occupied registers without 'willFree' registers; contains basically
3239 : // all the registers we can use to allocate variables without inRegs
3240 : // speficied.
3241 4908 : uint32_t occupied = state->_occupied.get(C) & ~willFree;
3242 : uint32_t willSpill = 0;
3243 :
3244 : // Find the best registers for variables that are not allocated yet. Only
3245 : // useful for Gp registers used as call operand.
3246 9626 : for (i = 0; i < tiedCount; i++) {
3247 4718 : TiedReg* tied = &tiedArray[i];
3248 1636 : VirtReg* vreg = tied->vreg;
3249 :
3250 4718 : uint32_t vaFlags = tied->flags;
3251 4718 : if ((vaFlags & TiedReg::kRDone) != 0 || (vaFlags & TiedReg::kRReg) == 0)
3252 3910 : continue;
3253 :
3254 : // All registers except Gp used by call itself must have inPhysId.
3255 808 : uint32_t m = tied->inRegs;
3256 0 : if (C != X86Reg::kKindGp || m) {
3257 : ASMJIT_ASSERT(m != 0);
3258 : tied->setInPhysId(Utils::findFirstBit(m));
3259 808 : willSpill |= occupied & m;
3260 808 : continue;
3261 : }
3262 :
3263 0 : m = tied->allocableRegs & ~(willAlloc ^ m);
3264 : m = guessAlloc<C>(vreg, m);
3265 : ASMJIT_ASSERT(m != 0);
3266 :
3267 0 : uint32_t candidateRegs = m & ~occupied;
3268 0 : if (candidateRegs == 0) {
3269 0 : candidateRegs = m & occupied & ~state->_modified.get(C);
3270 0 : if (candidateRegs == 0)
3271 : candidateRegs = m;
3272 : }
3273 :
3274 0 : if (!(vaFlags & (TiedReg::kWReg | TiedReg::kUnuse)) && (candidateRegs & ~clobbered))
3275 : candidateRegs &= ~clobbered;
3276 :
3277 : uint32_t physId = Utils::findFirstBit(candidateRegs);
3278 : uint32_t regMask = Utils::mask(physId);
3279 :
3280 : tied->setInPhysId(physId);
3281 0 : tied->inRegs = regMask;
3282 :
3283 0 : willAlloc |= regMask;
3284 0 : willSpill |= regMask & occupied;
3285 : willFree &= ~regMask;
3286 :
3287 0 : occupied |= regMask;
3288 0 : continue;
3289 : }
3290 :
3291 : // Set calculated masks back to the allocator; needed by spill() and alloc().
3292 : _willSpill.set(C, willSpill);
3293 : _willAlloc.set(C, willAlloc);
3294 : }
3295 :
3296 : template<int C>
3297 : ASMJIT_INLINE void X86CallAlloc::spill() {
3298 : uint32_t m = _willSpill.get(C);
3299 : uint32_t i = static_cast<uint32_t>(0) - 1;
3300 :
3301 1636 : if (m == 0)
3302 : return;
3303 :
3304 : X86RAState* state = getState();
3305 : VirtReg** sVars = state->getListByKind(C);
3306 :
3307 : // Available registers for decision if move has any benefit over spill.
3308 : uint32_t availableRegs = getGaRegs(C) & ~(state->_occupied.get(C) | m | _willAlloc.get(C));
3309 :
3310 : do {
3311 : // We always advance one more to destroy the bit that we have found.
3312 410 : uint32_t bitIndex = Utils::findFirstBit(m) + 1;
3313 :
3314 410 : i += bitIndex;
3315 410 : m >>= bitIndex;
3316 :
3317 410 : VirtReg* vreg = sVars[i];
3318 : ASMJIT_ASSERT(vreg && !vreg->_tied);
3319 :
3320 : if (vreg->isModified() && availableRegs) {
3321 : uint32_t available = guessSpill<C>(vreg, availableRegs);
3322 : if (available != 0) {
3323 : uint32_t physId = Utils::findFirstBit(available);
3324 : uint32_t regMask = Utils::mask(physId);
3325 :
3326 : _context->move<C>(vreg, physId);
3327 : availableRegs ^= regMask;
3328 : continue;
3329 : }
3330 : }
3331 :
3332 410 : _context->spill<C>(vreg);
3333 410 : } while (m != 0);
3334 : }
3335 :
3336 : template<int C>
3337 : ASMJIT_INLINE void X86CallAlloc::alloc() {
3338 1636 : if (isTiedDone(C)) return;
3339 :
3340 : TiedReg* tiedArray = getTiedArrayByKind(C);
3341 : uint32_t tiedCount = getTiedCountByKind(C);
3342 :
3343 : uint32_t i;
3344 : bool didWork;
3345 :
3346 1616 : do {
3347 : didWork = false;
3348 4872 : for (i = 0; i < tiedCount; i++) {
3349 3256 : TiedReg* aTied = &tiedArray[i];
3350 3256 : VirtReg* aVReg = aTied->vreg;
3351 3256 : if ((aTied->flags & (TiedReg::kRReg | TiedReg::kRDone)) != TiedReg::kRReg) continue;
3352 :
3353 : uint32_t sPhysId = aVReg->getPhysId();
3354 808 : uint32_t bPhysId = aTied->inPhysId;
3355 :
3356 : // Shouldn't be the same.
3357 : ASMJIT_ASSERT(sPhysId != bPhysId);
3358 :
3359 808 : VirtReg* bVReg = getState()->getListByKind(C)[bPhysId];
3360 808 : if (bVReg) {
3361 0 : TiedReg* bTied = bVReg->_tied;
3362 :
3363 : // GP registers only - Swap two registers if we can solve two
3364 : // allocation tasks by a single 'xchg' instruction, swapping
3365 : // two registers required by the instruction/node or one register
3366 : // required with another non-required.
3367 : if (C == X86Reg::kKindGp) {
3368 : _context->swapGp(aVReg, bVReg);
3369 :
3370 0 : aTied->flags |= TiedReg::kRDone;
3371 : addTiedDone(C);
3372 :
3373 : // Double-hit, two registers allocated by a single swap.
3374 0 : if (bTied && bTied->inPhysId == sPhysId) {
3375 0 : bTied->flags |= TiedReg::kRDone;
3376 : addTiedDone(C);
3377 : }
3378 :
3379 : didWork = true;
3380 0 : continue;
3381 : }
3382 0 : }
3383 808 : else if (sPhysId != Globals::kInvalidRegId) {
3384 : _context->move<C>(aVReg, bPhysId);
3385 322 : _context->_clobberedRegs.or_(C, Utils::mask(bPhysId));
3386 :
3387 322 : aTied->flags |= TiedReg::kRDone;
3388 : addTiedDone(C);
3389 :
3390 : didWork = true;
3391 322 : continue;
3392 : }
3393 : else {
3394 : _context->alloc<C>(aVReg, bPhysId);
3395 486 : _context->_clobberedRegs.or_(C, Utils::mask(bPhysId));
3396 :
3397 486 : aTied->flags |= TiedReg::kRDone;
3398 : addTiedDone(C);
3399 :
3400 : didWork = true;
3401 486 : continue;
3402 : }
3403 : }
3404 : } while (didWork);
3405 : }
3406 :
3407 : // ============================================================================
3408 : // [asmjit::X86CallAlloc - AllocImmsOnStack]
3409 : // ============================================================================
3410 :
3411 : ASMJIT_INLINE void X86CallAlloc::allocImmsOnStack() {
3412 : CCFuncCall* node = getNode();
3413 : FuncDetail& fd = node->getDetail();
3414 :
3415 : uint32_t argCount = fd.getArgCount();
3416 1636 : Operand_* args = node->_args;
3417 :
3418 3486 : for (uint32_t i = 0; i < argCount; i++) {
3419 1850 : Operand_& op = args[i];
3420 1850 : if (!op.isImm()) continue;
3421 :
3422 : const Imm& imm = static_cast<const Imm&>(op);
3423 : const FuncDetail::Value& arg = fd.getArg(i);
3424 : uint32_t varType = arg.getTypeId();
3425 :
3426 404 : if (arg.byReg()) {
3427 404 : _context->emitImmToReg(varType, arg.getRegId(), &imm);
3428 : }
3429 : else {
3430 0 : X86Mem dst = x86::ptr(_context->_zsp, -static_cast<int>(_context->getGpSize()) + arg.getStackOffset());
3431 0 : _context->emitImmToStack(varType, &dst, &imm);
3432 : }
3433 : }
3434 : }
3435 :
3436 : // ============================================================================
3437 : // [asmjit::X86CallAlloc - Duplicate]
3438 : // ============================================================================
3439 :
3440 : template<int C>
3441 : ASMJIT_INLINE void X86CallAlloc::duplicate() {
3442 : TiedReg* tiedArray = getTiedArrayByKind(C);
3443 : uint32_t tiedCount = getTiedCountByKind(C);
3444 :
3445 6354 : for (uint32_t i = 0; i < tiedCount; i++) {
3446 4718 : TiedReg* tied = &tiedArray[i];
3447 4718 : if ((tied->flags & TiedReg::kRReg) == 0) continue;
3448 :
3449 3082 : uint32_t inRegs = tied->inRegs;
3450 3082 : if (!inRegs) continue;
3451 :
3452 1446 : VirtReg* vreg = tied->vreg;
3453 : uint32_t physId = vreg->getPhysId();
3454 :
3455 : ASMJIT_ASSERT(physId != Globals::kInvalidRegId);
3456 :
3457 1446 : inRegs &= ~Utils::mask(physId);
3458 1446 : if (!inRegs) continue;
3459 :
3460 0 : for (uint32_t dupIndex = 0; inRegs != 0; dupIndex++, inRegs >>= 1) {
3461 0 : if (inRegs & 0x1) {
3462 0 : _context->emitMove(vreg, dupIndex, physId, "Duplicate");
3463 0 : _context->_clobberedRegs.or_(C, Utils::mask(dupIndex));
3464 : }
3465 : }
3466 : }
3467 : }
3468 :
3469 : // ============================================================================
3470 : // [asmjit::X86CallAlloc - GuessAlloc / GuessSpill]
3471 : // ============================================================================
3472 :
3473 : template<int C>
3474 : ASMJIT_INLINE uint32_t X86CallAlloc::guessAlloc(VirtReg* vreg, uint32_t allocableRegs) {
3475 : ASMJIT_ASSERT(allocableRegs != 0);
3476 :
3477 : // Stop now if there is only one bit (register) set in 'allocableRegs' mask.
3478 : if (Utils::isPowerOf2(allocableRegs))
3479 : return allocableRegs;
3480 :
3481 : uint32_t i;
3482 : uint32_t safeRegs = allocableRegs;
3483 : uint32_t maxLookAhead = kCompilerDefaultLookAhead;
3484 :
3485 : // Look ahead and calculate mask of special registers on both - input/output.
3486 0 : CBNode* node = _node;
3487 0 : for (i = 0; i < maxLookAhead; i++) {
3488 : // Stop on `CCFuncRet` and `CBSentinel`.
3489 0 : if (node->hasFlag(CBNode::kFlagIsRet))
3490 : break;
3491 :
3492 : // Stop on conditional jump, we don't follow them.
3493 0 : if (node->hasFlag(CBNode::kFlagIsJcc))
3494 : break;
3495 :
3496 : // Advance on non-conditional jump.
3497 0 : if (node->hasFlag(CBNode::kFlagIsJmp)) {
3498 : node = static_cast<CBJump*>(node)->getTarget();
3499 : // Stop on jump that is not followed.
3500 0 : if (!node) break;
3501 : }
3502 :
3503 : node = node->getNext();
3504 : ASMJIT_ASSERT(node != nullptr);
3505 :
3506 : X86RAData* raData = node->getPassData<X86RAData>();
3507 0 : if (raData) {
3508 : TiedReg* tied = raData->findTiedByKind(C, vreg);
3509 0 : if (tied) {
3510 0 : uint32_t inRegs = tied->inRegs;
3511 0 : if (inRegs != 0) {
3512 : safeRegs = allocableRegs;
3513 0 : allocableRegs &= inRegs;
3514 :
3515 0 : if (allocableRegs == 0)
3516 0 : goto _UseSafeRegs;
3517 : else
3518 : return allocableRegs;
3519 : }
3520 : }
3521 :
3522 : safeRegs = allocableRegs;
3523 0 : allocableRegs &= ~(raData->inRegs.get(C) | raData->outRegs.get(C) | raData->clobberedRegs.get(C));
3524 :
3525 0 : if (allocableRegs == 0)
3526 : break;
3527 : }
3528 : }
3529 :
3530 0 : _UseSafeRegs:
3531 : return safeRegs;
3532 : }
3533 :
3534 : template<int C>
3535 : ASMJIT_INLINE uint32_t X86CallAlloc::guessSpill(VirtReg* vreg, uint32_t allocableRegs) {
3536 : ASMJIT_ASSERT(allocableRegs != 0);
3537 : return 0;
3538 : }
3539 :
3540 : // ============================================================================
3541 : // [asmjit::X86CallAlloc - Save]
3542 : // ============================================================================
3543 :
3544 : template<int C>
3545 : ASMJIT_INLINE void X86CallAlloc::save() {
3546 : X86RAState* state = getState();
3547 : VirtReg** sVars = state->getListByKind(C);
3548 :
3549 : uint32_t i;
3550 4908 : uint32_t affected = _raData->clobberedRegs.get(C) & state->_occupied.get(C) & state->_modified.get(C);
3551 :
3552 6444 : for (i = 0; affected != 0; i++, affected >>= 1) {
3553 4808 : if (affected & 0x1) {
3554 3936 : VirtReg* vreg = sVars[i];
3555 : ASMJIT_ASSERT(vreg != nullptr);
3556 : ASMJIT_ASSERT(vreg->isModified());
3557 :
3558 3936 : TiedReg* tied = vreg->_tied;
3559 3936 : if (!tied || (tied->flags & (TiedReg::kWReg | TiedReg::kUnuse)) == 0)
3560 3468 : _context->save<C>(vreg);
3561 : }
3562 : }
3563 : }
3564 :
3565 : // ============================================================================
3566 : // [asmjit::X86CallAlloc - Clobber]
3567 : // ============================================================================
3568 :
3569 : template<int C>
3570 : ASMJIT_INLINE void X86CallAlloc::clobber() {
3571 : X86RAState* state = getState();
3572 : VirtReg** sVars = state->getListByKind(C);
3573 :
3574 : uint32_t i;
3575 4908 : uint32_t affected = _raData->clobberedRegs.get(C) & state->_occupied.get(C);
3576 :
3577 6870 : for (i = 0; affected != 0; i++, affected >>= 1) {
3578 5234 : if (affected & 0x1) {
3579 4830 : VirtReg* vreg = sVars[i];
3580 : ASMJIT_ASSERT(vreg != nullptr);
3581 :
3582 4830 : TiedReg* tied = vreg->_tied;
3583 : uint32_t vdState = VirtReg::kStateNone;
3584 :
3585 4830 : if (!vreg->isModified() || (tied && (tied->flags & (TiedReg::kWAll | TiedReg::kUnuse)) != 0))
3586 : vdState = VirtReg::kStateMem;
3587 4830 : _context->unuse<C>(vreg, vdState);
3588 : }
3589 : }
3590 : }
3591 :
3592 : // ============================================================================
3593 : // [asmjit::X86CallAlloc - Ret]
3594 : // ============================================================================
3595 :
3596 : ASMJIT_INLINE void X86CallAlloc::ret() {
3597 : CCFuncCall* node = getNode();
3598 : FuncDetail& fd = node->getDetail();
3599 1636 : Operand_* rets = node->_ret;
3600 :
3601 4908 : for (uint32_t i = 0; i < 2; i++) {
3602 3272 : const FuncDetail::Value& ret = fd.getRet(i);
3603 3272 : Operand_* op = &rets[i];
3604 :
3605 3272 : if (!ret.byReg() || !op->isVirtReg())
3606 1636 : continue;
3607 :
3608 1636 : VirtReg* vreg = _cc->getVirtRegById(op->getId());
3609 : uint32_t regId = ret.getRegId();
3610 :
3611 1636 : switch (vreg->getKind()) {
3612 0 : case X86Reg::kKindGp:
3613 0 : _context->unuse<X86Reg::kKindGp>(vreg);
3614 0 : _context->attach<X86Reg::kKindGp>(vreg, regId, true);
3615 : break;
3616 :
3617 0 : case X86Reg::kKindMm:
3618 0 : _context->unuse<X86Reg::kKindMm>(vreg);
3619 0 : _context->attach<X86Reg::kKindMm>(vreg, regId, true);
3620 : break;
3621 :
3622 : case X86Reg::kKindVec:
3623 1636 : if (X86Reg::kindOf(ret.getRegType()) == X86Reg::kKindVec) {
3624 1636 : _context->unuse<X86Reg::kKindVec>(vreg);
3625 1636 : _context->attach<X86Reg::kKindVec>(vreg, regId, true);
3626 : }
3627 : else {
3628 : uint32_t elementId = TypeId::elementOf(vreg->getTypeId());
3629 0 : uint32_t size = (elementId == TypeId::kF32) ? 4 : 8;
3630 :
3631 0 : X86Mem m = _context->getVarMem(vreg);
3632 : m.setSize(size);
3633 :
3634 0 : _context->unuse<X86Reg::kKindVec>(vreg, VirtReg::kStateMem);
3635 0 : _cc->fstp(m);
3636 : }
3637 : break;
3638 : }
3639 : }
3640 : }
3641 :
3642 : // ============================================================================
3643 : // [asmjit::X86RAPass - TranslateOperands]
3644 : // ============================================================================
3645 :
3646 : //! \internal
3647 32742 : static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount) {
3648 : X86Compiler* cc = self->cc();
3649 :
3650 : // Translate variables into registers.
3651 96710 : for (uint32_t i = 0; i < opCount; i++) {
3652 63968 : Operand_* op = &opArray[i];
3653 : if (op->isVirtReg()) {
3654 : VirtReg* vreg = cc->getVirtRegById(op->getId());
3655 : ASMJIT_ASSERT(vreg != nullptr);
3656 : ASMJIT_ASSERT(vreg->getPhysId() != Globals::kInvalidRegId);
3657 50532 : op->_reg.id = vreg->getPhysId();
3658 : }
3659 13436 : else if (op->isMem()) {
3660 : X86Mem* m = static_cast<X86Mem*>(op);
3661 :
3662 6068 : if (m->hasBaseReg() && cc->isVirtRegValid(m->getBaseId())) {
3663 : VirtReg* vreg = cc->getVirtRegById(m->getBaseId());
3664 :
3665 6068 : if (m->isRegHome()) {
3666 0 : self->getVarCell(vreg);
3667 : }
3668 : else {
3669 : ASMJIT_ASSERT(vreg->getPhysId() != Globals::kInvalidRegId);
3670 6068 : op->_mem.base = vreg->getPhysId();
3671 : }
3672 : }
3673 :
3674 6068 : if (m->hasIndexReg() && cc->isVirtRegValid(m->getIndexId())) {
3675 : VirtReg* vreg = cc->getVirtRegById(m->getIndexId());
3676 0 : op->_mem.index = vreg->getPhysId();
3677 : }
3678 : }
3679 : }
3680 :
3681 32742 : return kErrorOk;
3682 : }
3683 :
3684 : // ============================================================================
3685 : // [asmjit::X86RAPass - TranslatePrologEpilog]
3686 : // ============================================================================
3687 :
3688 : //! \internal
3689 1944 : static Error X86RAPass_prepareFuncFrame(X86RAPass* self, CCFunc* func) {
3690 : FuncFrameInfo& ffi = func->getFrameInfo();
3691 :
3692 : X86RegMask& clobberedRegs = self->_clobberedRegs;
3693 :
3694 : // Initialize dirty registers.
3695 : ffi.setDirtyRegs(X86Reg::kKindGp , clobberedRegs.get(X86Reg::kKindGp ));
3696 : ffi.setDirtyRegs(X86Reg::kKindMm , clobberedRegs.get(X86Reg::kKindMm ));
3697 : ffi.setDirtyRegs(X86Reg::kKindK , clobberedRegs.get(X86Reg::kKindK ));
3698 : ffi.setDirtyRegs(X86Reg::kKindVec, clobberedRegs.get(X86Reg::kKindVec));
3699 :
3700 : // Initialize stack size & alignment.
3701 1944 : ffi.setStackFrameSize(self->_memAllTotal);
3702 1944 : ffi.setStackFrameAlignment(self->_memMaxAlign);
3703 :
3704 1944 : return kErrorOk;
3705 : }
3706 :
3707 : //! \internal
3708 1944 : static Error X86RAPass_patchFuncMem(X86RAPass* self, CCFunc* func, CBNode* stop, FuncFrameLayout& layout) {
3709 : X86Compiler* cc = self->cc();
3710 : CBNode* node = func;
3711 :
3712 : do {
3713 50006 : if (node->getType() == CBNode::kNodeInst) {
3714 : CBInst* iNode = static_cast<CBInst*>(node);
3715 :
3716 40594 : if (iNode->hasMemOp()) {
3717 : X86Mem* m = iNode->getMemOp<X86Mem>();
3718 :
3719 14496 : if (m->isArgHome()) {
3720 : m->addOffsetLo32(layout.getStackArgsOffset());
3721 : m->clearArgHome();
3722 : }
3723 :
3724 14496 : if (m->isRegHome() && Operand::isPackedId(m->getBaseId())) {
3725 : VirtReg* vreg = cc->getVirtRegById(m->getBaseId());
3726 : ASMJIT_ASSERT(vreg != nullptr);
3727 :
3728 : RACell* cell = vreg->getMemCell();
3729 : ASMJIT_ASSERT(cell != nullptr);
3730 :
3731 8428 : m->_setBase(cc->_nativeGpReg.getType(), self->_varBaseRegId);
3732 8428 : m->addOffsetLo32(self->_varBaseOffset + cell->offset);
3733 : m->clearRegHome();
3734 : }
3735 : }
3736 : }
3737 :
3738 : node = node->getNext();
3739 50006 : } while (node != stop);
3740 :
3741 1944 : return kErrorOk;
3742 : }
3743 :
3744 : // ============================================================================
3745 : // [asmjit::X86RAPass - Translate - Jump]
3746 : // ============================================================================
3747 :
3748 : //! \internal
3749 0 : static void X86RAPass_translateJump(X86RAPass* self, CBJump* jNode, CBLabel* jTarget) {
3750 : X86Compiler* cc = self->cc();
3751 :
3752 : CBNode* injectRef = self->getFunc()->getEnd()->getPrev();
3753 0 : CBNode* prevCursor = cc->setCursor(injectRef);
3754 :
3755 0 : self->switchState(jTarget->getPassData<RAData>()->state);
3756 :
3757 : // Any code necessary to `switchState()` will be added at the end of the function.
3758 0 : if (cc->getCursor() != injectRef) {
3759 : // TODO: Can fail.
3760 0 : CBLabel* injectLabel = cc->newLabelNode();
3761 :
3762 : // Add the jump to the target.
3763 0 : cc->jmp(jTarget->getLabel());
3764 :
3765 : // Inject the label.
3766 : cc->_setCursor(injectRef);
3767 0 : cc->addNode(injectLabel);
3768 :
3769 : // Finally, patch `jNode` target.
3770 : ASMJIT_ASSERT(jNode->getOpCount() > 0);
3771 0 : jNode->_opArray[jNode->getOpCount() - 1] = injectLabel->getLabel();
3772 0 : jNode->_target = injectLabel;
3773 : // If we injected any code it may not satisfy short form anymore.
3774 : jNode->delOptions(X86Inst::kOptionShortForm);
3775 : }
3776 :
3777 : cc->_setCursor(prevCursor);
3778 0 : self->loadState(jNode->getPassData<RAData>()->state);
3779 0 : }
3780 :
3781 : // ============================================================================
3782 : // [asmjit::X86RAPass - Translate - Ret]
3783 : // ============================================================================
3784 :
3785 1944 : static Error X86RAPass_translateRet(X86RAPass* self, CCFuncRet* rNode, CBLabel* exitTarget) {
3786 : X86Compiler* cc = self->cc();
3787 : CBNode* node = rNode->getNext();
3788 :
3789 : // 32-bit mode requires to push floating point return value(s), handle it
3790 : // here as it's a special case.
3791 : X86RAData* raData = rNode->getPassData<X86RAData>();
3792 1944 : if (raData) {
3793 1944 : TiedReg* tiedArray = raData->tiedArray;
3794 1944 : uint32_t tiedTotal = raData->tiedTotal;
3795 :
3796 3888 : for (uint32_t i = 0; i < tiedTotal; i++) {
3797 1944 : TiedReg* tied = &tiedArray[i];
3798 1944 : if (tied->flags & (TiedReg::kX86Fld4 | TiedReg::kX86Fld8)) {
3799 0 : VirtReg* vreg = tied->vreg;
3800 : X86Mem m(self->getVarMem(vreg));
3801 :
3802 : uint32_t elementId = TypeId::elementOf(vreg->getTypeId());
3803 0 : m.setSize(elementId == TypeId::kF32 ? 4 :
3804 : elementId == TypeId::kF64 ? 8 :
3805 0 : (tied->flags & TiedReg::kX86Fld4) ? 4 : 8);
3806 :
3807 : cc->fld(m);
3808 : }
3809 : }
3810 : }
3811 :
3812 : // Decide whether to `jmp` or not in case we are next to the return label.
3813 1944 : while (node) {
3814 1944 : switch (node->getType()) {
3815 : // If we have found an exit label we just return, there is no need to
3816 : // emit jump to that.
3817 1944 : case CBNode::kNodeLabel:
3818 1944 : if (static_cast<CBLabel*>(node) == exitTarget)
3819 : return kErrorOk;
3820 0 : goto _EmitRet;
3821 :
3822 0 : case CBNode::kNodeData:
3823 : case CBNode::kNodeInst:
3824 : case CBNode::kNodeFuncCall:
3825 : case CBNode::kNodeFuncExit:
3826 0 : goto _EmitRet;
3827 :
3828 : // Continue iterating.
3829 : case CBNode::kNodeComment:
3830 : case CBNode::kNodeAlign:
3831 : case CBNode::kNodeHint:
3832 : break;
3833 :
3834 : // Invalid node to be here.
3835 : case CBNode::kNodeFunc:
3836 : return DebugUtils::errored(kErrorInvalidState);
3837 :
3838 : // We can't go forward from here.
3839 0 : case CBNode::kNodeSentinel:
3840 0 : return kErrorOk;
3841 : }
3842 :
3843 : node = node->getNext();
3844 : }
3845 :
3846 0 : _EmitRet:
3847 : {
3848 : cc->_setCursor(rNode);
3849 0 : cc->jmp(exitTarget->getLabel());
3850 : }
3851 0 : return kErrorOk;
3852 : }
3853 :
3854 : // ============================================================================
3855 : // [asmjit::X86RAPass - Translate - Func]
3856 : // ============================================================================
3857 :
3858 1944 : Error X86RAPass::translate() {
3859 : X86Compiler* cc = this->cc();
3860 : CCFunc* func = getFunc();
3861 :
3862 : // Register allocator contexts.
3863 : X86VarAlloc vAlloc(this);
3864 : X86CallAlloc cAlloc(this);
3865 :
3866 : // Flow.
3867 : CBNode* node_ = func;
3868 : CBNode* next = nullptr;
3869 : CBNode* stop = getStop();
3870 :
3871 : ZoneList<CBNode*>::Link* jLink = _jccList.getFirst();
3872 :
3873 : for (;;) {
3874 36630 : while (node_->isTranslated()) {
3875 : // Switch state if we went to a node that is already translated.
3876 0 : if (node_->getType() == CBNode::kNodeLabel) {
3877 : CBLabel* node = static_cast<CBLabel*>(node_);
3878 : cc->_setCursor(node->getPrev());
3879 0 : switchState(node->getPassData<RAData>()->state);
3880 : }
3881 :
3882 0 : _NextGroup:
3883 1944 : if (!jLink) {
3884 1944 : goto _Done;
3885 : }
3886 : else {
3887 : node_ = jLink->getValue();
3888 : jLink = jLink->getNext();
3889 :
3890 : CBNode* jFlow = X86RAPass_getOppositeJccFlow(static_cast<CBJump*>(node_));
3891 0 : loadState(node_->getPassData<RAData>()->state);
3892 :
3893 0 : if (jFlow->hasPassData() && jFlow->getPassData<RAData>()->state) {
3894 0 : X86RAPass_translateJump(this, static_cast<CBJump*>(node_), static_cast<CBLabel*>(jFlow));
3895 :
3896 : node_ = jFlow;
3897 0 : if (node_->isTranslated())
3898 0 : goto _NextGroup;
3899 : }
3900 : else {
3901 : node_ = jFlow;
3902 : }
3903 :
3904 : break;
3905 : }
3906 : }
3907 :
3908 : next = node_->getNext();
3909 36630 : node_->_flags |= CBNode::kFlagIsTranslated;
3910 :
3911 36630 : if (node_->hasPassData()) {
3912 36630 : switch (node_->getType()) {
3913 : // --------------------------------------------------------------------
3914 : // [Align / Embed]
3915 : // --------------------------------------------------------------------
3916 :
3917 : case CBNode::kNodeAlign:
3918 : case CBNode::kNodeData:
3919 : break;
3920 :
3921 : // --------------------------------------------------------------------
3922 : // [Label]
3923 : // --------------------------------------------------------------------
3924 :
3925 0 : case CBNode::kNodeLabel: {
3926 : CBLabel* node = static_cast<CBLabel*>(node_);
3927 : ASMJIT_ASSERT(node->getPassData<RAData>()->state == nullptr);
3928 0 : node->getPassData<RAData>()->state = saveState();
3929 :
3930 0 : if (node == func->getExitNode())
3931 0 : goto _NextGroup;
3932 : break;
3933 : }
3934 :
3935 : // --------------------------------------------------------------------
3936 : // [Inst/Call/SArg/Ret]
3937 : // --------------------------------------------------------------------
3938 :
3939 : case CBNode::kNodeInst:
3940 : case CBNode::kNodeFunc:
3941 : case CBNode::kNodeFuncCall:
3942 : case CBNode::kNodePushArg:
3943 : // Update TiedReg's unuse flags based on liveness of the next node.
3944 34686 : if (!node_->isJcc()) {
3945 : X86RAData* raData = node_->getPassData<X86RAData>();
3946 : RABits* liveness;
3947 :
3948 34686 : if (raData && next && next->hasPassData() && (liveness = next->getPassData<RAData>()->liveness)) {
3949 34686 : TiedReg* tiedArray = raData->tiedArray;
3950 34686 : uint32_t tiedTotal = raData->tiedTotal;
3951 :
3952 94116 : for (uint32_t i = 0; i < tiedTotal; i++) {
3953 59430 : TiedReg* tied = &tiedArray[i];
3954 59430 : VirtReg* vreg = tied->vreg;
3955 :
3956 59430 : if (!liveness->getBit(vreg->_raId) && !vreg->isFixed())
3957 21796 : tied->flags |= TiedReg::kUnuse;
3958 : }
3959 : }
3960 : }
3961 :
3962 34686 : if (node_->getType() == CBNode::kNodeFuncCall) {
3963 1636 : ASMJIT_PROPAGATE(cAlloc.run(static_cast<CCFuncCall*>(node_)));
3964 : break;
3965 : }
3966 : ASMJIT_FALLTHROUGH;
3967 :
3968 : case CBNode::kNodeHint:
3969 : case CBNode::kNodeFuncExit: {
3970 34994 : ASMJIT_PROPAGATE(vAlloc.run(node_));
3971 :
3972 : // Handle conditional/unconditional jump.
3973 34994 : if (node_->isJmpOrJcc()) {
3974 : CBJump* node = static_cast<CBJump*>(node_);
3975 : CBLabel* jTarget = node->getTarget();
3976 :
3977 : // Target not followed.
3978 0 : if (!jTarget) {
3979 0 : if (node->isJmp())
3980 0 : goto _NextGroup;
3981 : else
3982 : break;
3983 : }
3984 :
3985 0 : if (node->isJmp()) {
3986 0 : if (jTarget->hasPassData() && jTarget->getPassData<RAData>()->state) {
3987 : cc->_setCursor(node->getPrev());
3988 0 : switchState(jTarget->getPassData<RAData>()->state);
3989 :
3990 0 : goto _NextGroup;
3991 : }
3992 : else {
3993 : next = jTarget;
3994 : }
3995 : }
3996 : else {
3997 : CBNode* jNext = node->getNext();
3998 :
3999 0 : if (jTarget->isTranslated()) {
4000 0 : if (jNext->isTranslated()) {
4001 : ASMJIT_ASSERT(jNext->getType() == CBNode::kNodeLabel);
4002 : cc->_setCursor(node->getPrev());
4003 0 : intersectStates(
4004 : jTarget->getPassData<RAData>()->state,
4005 : jNext->getPassData<RAData>()->state);
4006 : }
4007 :
4008 0 : RAState* savedState = saveState();
4009 0 : node->getPassData<RAData>()->state = savedState;
4010 :
4011 0 : X86RAPass_translateJump(this, node, jTarget);
4012 : next = jNext;
4013 : }
4014 0 : else if (jNext->isTranslated()) {
4015 : ASMJIT_ASSERT(jNext->getType() == CBNode::kNodeLabel);
4016 :
4017 0 : RAState* savedState = saveState();
4018 0 : node->getPassData<RAData>()->state = savedState;
4019 :
4020 : cc->_setCursor(node);
4021 0 : switchState(jNext->getPassData<RAData>()->state);
4022 : next = jTarget;
4023 : }
4024 : else {
4025 0 : node->getPassData<RAData>()->state = saveState();
4026 : next = X86RAPass_getJccFlow(node);
4027 : }
4028 : }
4029 : }
4030 34994 : else if (node_->isRet()) {
4031 1944 : ASMJIT_PROPAGATE(
4032 : X86RAPass_translateRet(this, static_cast<CCFuncRet*>(node_), func->getExitNode()));
4033 1944 : goto _NextGroup;
4034 : }
4035 : break;
4036 : }
4037 :
4038 : // --------------------------------------------------------------------
4039 : // [End]
4040 : // --------------------------------------------------------------------
4041 :
4042 0 : case CBNode::kNodeSentinel: {
4043 0 : goto _NextGroup;
4044 : }
4045 :
4046 : default:
4047 : break;
4048 : }
4049 : }
4050 :
4051 34686 : if (next == stop)
4052 0 : goto _NextGroup;
4053 : node_ = next;
4054 : }
4055 :
4056 : _Done:
4057 : {
4058 1944 : ASMJIT_PROPAGATE(resolveCellOffsets());
4059 1944 : ASMJIT_PROPAGATE(X86RAPass_prepareFuncFrame(this, func));
4060 :
4061 : FuncFrameLayout layout;
4062 1944 : ASMJIT_PROPAGATE(layout.init(func->getDetail(), func->getFrameInfo()));
4063 :
4064 1944 : _varBaseRegId = layout._stackBaseRegId;
4065 1944 : _varBaseOffset = layout._stackBaseOffset;
4066 :
4067 1944 : ASMJIT_PROPAGATE(X86RAPass_patchFuncMem(this, func, stop, layout));
4068 :
4069 : cc->_setCursor(func);
4070 1944 : ASMJIT_PROPAGATE(FuncUtils::emitProlog(this->cc(), layout));
4071 :
4072 : cc->_setCursor(func->getExitNode());
4073 1944 : ASMJIT_PROPAGATE(FuncUtils::emitEpilog(this->cc(), layout));
4074 : }
4075 :
4076 1944 : return kErrorOk;
4077 : }
4078 :
4079 : } // asmjit namespace
4080 : } // namespace PLMD
4081 :
4082 : // [Api-End]
4083 : #include "./asmjit_apiend.h"
4084 :
4085 : // [Guard]
4086 : #endif // ASMJIT_BUILD_X86 && !ASMJIT_DISABLE_COMPILER
4087 : #pragma GCC diagnostic pop
4088 : #endif // __PLUMED_HAS_ASMJIT
|