Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #include "api-build_p.h"
8 : #if !defined(ASMJIT_NO_X86)
9 :
10 : #include "formatter.h"
11 : #include "funcargscontext_p.h"
12 : #include "moved_string.h"
13 : #include "support.h"
14 : #include "type.h"
15 : #include "radefs_p.h"
16 : #include "x86emithelper_p.h"
17 : #include "x86emitter.h"
18 : #include "x86formatter_p.h"
19 : #include "x86instapi_p.h"
20 :
21 : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
22 :
23 : // x86::EmitHelper - Utilities
24 : // ===========================
25 :
26 : static inline uint32_t getXmmMovInst(const FuncFrame& frame) {
27 : bool avx = frame.isAvxEnabled();
28 : bool aligned = frame.hasAlignedVecSR();
29 :
30 0 : return aligned ? (avx ? Inst::kIdVmovaps : Inst::kIdMovaps)
31 : : (avx ? Inst::kIdVmovups : Inst::kIdMovups);
32 : }
33 :
34 : //! Converts `size` to a 'kmov?' instruction.
35 0 : static inline uint32_t kmovInstFromSize(uint32_t size) noexcept {
36 0 : switch (size) {
37 : case 1: return Inst::kIdKmovb;
38 0 : case 2: return Inst::kIdKmovw;
39 0 : case 4: return Inst::kIdKmovd;
40 0 : case 8: return Inst::kIdKmovq;
41 0 : default: return Inst::kIdNone;
42 : }
43 : }
44 :
45 : static inline uint32_t makeCastOp(TypeId dst, TypeId src) noexcept {
46 0 : return (uint32_t(dst) << 8) | uint32_t(src);
47 : }
48 :
49 : // x86::EmitHelper - Emit Reg Move
50 : // ===============================
51 :
52 50221 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove(
53 : const Operand_& dst_,
54 : const Operand_& src_, TypeId typeId, const char* comment) {
55 :
56 : // Invalid or abstract TypeIds are not allowed.
57 : ASMJIT_ASSERT(TypeUtils::isValid(typeId) && !TypeUtils::isAbstract(typeId));
58 :
59 : Operand dst(dst_);
60 : Operand src(src_);
61 :
62 : InstId instId = Inst::kIdNone;
63 : uint32_t memFlags = 0;
64 : uint32_t overrideMemSize = 0;
65 :
66 : enum MemFlags : uint32_t {
67 : kDstMem = 0x1,
68 : kSrcMem = 0x2
69 : };
70 :
71 : // Detect memory operands and patch them to have the same size as the register. BaseCompiler always sets memory size
72 : // of allocs and spills, so it shouldn't be really necessary, however, after this function was separated from Compiler
73 : // it's better to make sure that the size is always specified, as we can use 'movzx' and 'movsx' that rely on it.
74 50221 : if (dst.isMem()) { memFlags |= kDstMem; dst.as<Mem>().setSize(src.size()); }
75 50221 : if (src.isMem()) { memFlags |= kSrcMem; src.as<Mem>().setSize(dst.size()); }
76 :
77 50221 : switch (typeId) {
78 0 : case TypeId::kInt8:
79 : case TypeId::kUInt8:
80 : case TypeId::kInt16:
81 : case TypeId::kUInt16:
82 : // Special case - 'movzx' load.
83 0 : if (memFlags & kSrcMem) {
84 : instId = Inst::kIdMovzx;
85 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
86 : break;
87 : }
88 :
89 0 : if (!memFlags) {
90 : // Change both destination and source registers to GPD (safer, no dependencies).
91 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
92 : src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
93 : }
94 : ASMJIT_FALLTHROUGH;
95 :
96 : case TypeId::kInt32:
97 : case TypeId::kUInt32:
98 : case TypeId::kInt64:
99 : case TypeId::kUInt64:
100 : instId = Inst::kIdMov;
101 : break;
102 :
103 0 : case TypeId::kMmx32:
104 : instId = Inst::kIdMovd;
105 0 : if (memFlags) break;
106 : ASMJIT_FALLTHROUGH;
107 :
108 : case TypeId::kMmx64 : instId = Inst::kIdMovq ; break;
109 : case TypeId::kMask8 : instId = Inst::kIdKmovb; break;
110 : case TypeId::kMask16: instId = Inst::kIdKmovw; break;
111 : case TypeId::kMask32: instId = Inst::kIdKmovd; break;
112 : case TypeId::kMask64: instId = Inst::kIdKmovq; break;
113 :
114 : default: {
115 : TypeId scalarTypeId = TypeUtils::scalarOf(typeId);
116 50201 : if (TypeUtils::isVec32(typeId) && memFlags) {
117 : overrideMemSize = 4;
118 0 : if (scalarTypeId == TypeId::kFloat32)
119 0 : instId = _avxEnabled ? Inst::kIdVmovss : Inst::kIdMovss;
120 : else
121 0 : instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
122 : break;
123 : }
124 :
125 50201 : if (TypeUtils::isVec64(typeId) && memFlags) {
126 : overrideMemSize = 8;
127 48416 : if (scalarTypeId == TypeId::kFloat64)
128 48416 : instId = _avxEnabled ? Inst::kIdVmovsd : Inst::kIdMovsd;
129 : else
130 0 : instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
131 : break;
132 : }
133 :
134 1785 : if (scalarTypeId == TypeId::kFloat32)
135 0 : instId = _avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps;
136 1785 : else if (scalarTypeId == TypeId::kFloat64)
137 1785 : instId = _avxEnabled ? Inst::kIdVmovapd : Inst::kIdMovapd;
138 0 : else if (!_avx512Enabled)
139 0 : instId = _avxEnabled ? Inst::kIdVmovdqa : Inst::kIdMovdqa;
140 : else
141 : instId = Inst::kIdVmovdqa32;
142 : break;
143 : }
144 : }
145 :
146 : if (!instId)
147 : return DebugUtils::errored(kErrorInvalidState);
148 :
149 50221 : if (overrideMemSize) {
150 48416 : if (dst.isMem()) dst.as<Mem>().setSize(overrideMemSize);
151 48416 : if (src.isMem()) src.as<Mem>().setSize(overrideMemSize);
152 : }
153 :
154 50221 : _emitter->setInlineComment(comment);
155 50221 : return _emitter->emit(instId, dst, src);
156 : }
157 :
158 : // x86::EmitHelper - Emit Arg Move
159 : // ===============================
160 :
161 0 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitArgMove(
162 : const BaseReg& dst_, TypeId dstTypeId,
163 : const Operand_& src_, TypeId srcTypeId, const char* comment) {
164 :
165 : // Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
166 0 : if (dstTypeId == TypeId::kVoid) {
167 0 : const ArchTraits& archTraits = ArchTraits::byArch(_emitter->arch());
168 : dstTypeId = archTraits.regTypeToTypeId(dst_.type());
169 : }
170 :
171 : // Invalid or abstract TypeIds are not allowed.
172 : ASMJIT_ASSERT(TypeUtils::isValid(dstTypeId) && !TypeUtils::isAbstract(dstTypeId));
173 : ASMJIT_ASSERT(TypeUtils::isValid(srcTypeId) && !TypeUtils::isAbstract(srcTypeId));
174 :
175 : Reg dst(dst_.as<Reg>());
176 : Operand src(src_);
177 :
178 : uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
179 : uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
180 :
181 : InstId instId = Inst::kIdNone;
182 :
183 : // Not a real loop, just 'break' is nicer than 'goto'.
184 : for (;;) {
185 0 : if (TypeUtils::isInt(dstTypeId)) {
186 0 : if (TypeUtils::isInt(srcTypeId)) {
187 : instId = Inst::kIdMovsx;
188 : uint32_t castOp = makeCastOp(dstTypeId, srcTypeId);
189 :
190 : // Sign extend by using 'movsx'.
191 : if (castOp == makeCastOp(TypeId::kInt16, TypeId::kInt8 ) ||
192 : castOp == makeCastOp(TypeId::kInt32, TypeId::kInt8 ) ||
193 : castOp == makeCastOp(TypeId::kInt32, TypeId::kInt16) ||
194 : castOp == makeCastOp(TypeId::kInt64, TypeId::kInt8 ) ||
195 : castOp == makeCastOp(TypeId::kInt64, TypeId::kInt16))
196 : break;
197 :
198 : // Sign extend by using 'movsxd'.
199 : instId = Inst::kIdMovsxd;
200 : if (castOp == makeCastOp(TypeId::kInt64, TypeId::kInt32))
201 : break;
202 : }
203 :
204 0 : if (TypeUtils::isInt(srcTypeId) || src_.isMem()) {
205 : // Zero extend by using 'movzx' or 'mov'.
206 0 : if (dstSize <= 4 && srcSize < 4) {
207 : instId = Inst::kIdMovzx;
208 0 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
209 : }
210 : else {
211 : // We should have caught all possibilities where `srcSize` is less than 4, so we don't have to worry
212 : // about 'movzx' anymore. Minimum size is enough to determine if we want 32-bit or 64-bit move.
213 : instId = Inst::kIdMov;
214 : srcSize = Support::min(srcSize, dstSize);
215 :
216 0 : dst.setSignature(srcSize == 4 ? Reg::signatureOfT<RegType::kX86_Gpd>()
217 : : Reg::signatureOfT<RegType::kX86_Gpq>());
218 0 : if (src.isReg())
219 : src.setSignature(dst.signature());
220 : }
221 : break;
222 : }
223 :
224 : // NOTE: The previous branch caught all memory sources, from here it's always register to register conversion,
225 : // so catch the remaining cases.
226 : srcSize = Support::min(srcSize, dstSize);
227 :
228 0 : if (TypeUtils::isMmx(srcTypeId)) {
229 : // 64-bit move.
230 : instId = Inst::kIdMovq;
231 0 : if (srcSize == 8)
232 : break;
233 :
234 : // 32-bit move.
235 : instId = Inst::kIdMovd;
236 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
237 0 : break;
238 : }
239 :
240 0 : if (TypeUtils::isMask(srcTypeId)) {
241 0 : instId = kmovInstFromSize(srcSize);
242 0 : dst.setSignature(srcSize <= 4 ? Reg::signatureOfT<RegType::kX86_Gpd>()
243 : : Reg::signatureOfT<RegType::kX86_Gpq>());
244 0 : break;
245 : }
246 :
247 0 : if (TypeUtils::isVec(srcTypeId)) {
248 : // 64-bit move.
249 0 : instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
250 0 : if (srcSize == 8)
251 : break;
252 :
253 : // 32-bit move.
254 0 : instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
255 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
256 0 : break;
257 : }
258 : }
259 :
260 0 : if (TypeUtils::isMmx(dstTypeId)) {
261 : instId = Inst::kIdMovq;
262 : srcSize = Support::min(srcSize, dstSize);
263 :
264 0 : if (TypeUtils::isInt(srcTypeId) || src.isMem()) {
265 : // 64-bit move.
266 0 : if (srcSize == 8)
267 : break;
268 :
269 : // 32-bit move.
270 : instId = Inst::kIdMovd;
271 0 : if (src.isReg())
272 : src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
273 : break;
274 : }
275 :
276 0 : if (TypeUtils::isMmx(srcTypeId))
277 : break;
278 :
279 : // This will hurt if AVX is enabled.
280 : instId = Inst::kIdMovdq2q;
281 0 : if (TypeUtils::isVec(srcTypeId))
282 : break;
283 : }
284 :
285 0 : if (TypeUtils::isMask(dstTypeId)) {
286 : srcSize = Support::min(srcSize, dstSize);
287 :
288 0 : if (TypeUtils::isInt(srcTypeId) || TypeUtils::isMask(srcTypeId) || src.isMem()) {
289 0 : instId = kmovInstFromSize(srcSize);
290 0 : if (Reg::isGp(src) && srcSize <= 4)
291 : src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
292 : break;
293 : }
294 : }
295 :
296 0 : if (TypeUtils::isVec(dstTypeId)) {
297 : // By default set destination to XMM, will be set to YMM|ZMM if needed.
298 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Xmm>());
299 :
300 : // This will hurt if AVX is enabled.
301 0 : if (Reg::isMm(src)) {
302 : // 64-bit move.
303 : instId = Inst::kIdMovq2dq;
304 : break;
305 : }
306 :
307 : // Argument conversion.
308 : TypeId dstScalarId = TypeUtils::scalarOf(dstTypeId);
309 : TypeId srcScalarId = TypeUtils::scalarOf(srcTypeId);
310 :
311 0 : if (dstScalarId == TypeId::kFloat32 && srcScalarId == TypeId::kFloat64) {
312 0 : srcSize = Support::min(dstSize * 2, srcSize);
313 0 : dstSize = srcSize / 2;
314 :
315 0 : if (srcSize <= 8)
316 0 : instId = _avxEnabled ? Inst::kIdVcvtss2sd : Inst::kIdCvtss2sd;
317 : else
318 0 : instId = _avxEnabled ? Inst::kIdVcvtps2pd : Inst::kIdCvtps2pd;
319 :
320 0 : if (dstSize == 32)
321 : dst.setSignature(Reg::signatureOfT<RegType::kX86_Ymm>());
322 0 : if (src.isReg())
323 0 : src.setSignature(Reg::signatureOfVecBySize(srcSize));
324 : break;
325 : }
326 :
327 0 : if (dstScalarId == TypeId::kFloat64 && srcScalarId == TypeId::kFloat32) {
328 0 : srcSize = Support::min(dstSize, srcSize * 2) / 2;
329 0 : dstSize = srcSize * 2;
330 :
331 0 : if (srcSize <= 4)
332 0 : instId = _avxEnabled ? Inst::kIdVcvtsd2ss : Inst::kIdCvtsd2ss;
333 : else
334 0 : instId = _avxEnabled ? Inst::kIdVcvtpd2ps : Inst::kIdCvtpd2ps;
335 :
336 0 : dst.setSignature(Reg::signatureOfVecBySize(dstSize));
337 0 : if (src.isReg() && srcSize >= 32)
338 : src.setSignature(Reg::signatureOfT<RegType::kX86_Ymm>());
339 : break;
340 : }
341 :
342 : srcSize = Support::min(srcSize, dstSize);
343 0 : if (Reg::isGp(src) || src.isMem()) {
344 : // 32-bit move.
345 0 : if (srcSize <= 4) {
346 0 : instId = _avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd;
347 : if (src.isReg())
348 : src.setSignature(Reg::signatureOfT<RegType::kX86_Gpd>());
349 : break;
350 : }
351 :
352 : // 64-bit move.
353 0 : if (srcSize == 8) {
354 0 : instId = _avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq;
355 : break;
356 : }
357 : }
358 :
359 0 : if (Reg::isVec(src) || src.isMem()) {
360 0 : instId = _avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps;
361 :
362 0 : if (src.isMem() && srcSize < _emitter->environment().stackAlignment())
363 0 : instId = _avxEnabled ? Inst::kIdVmovups : Inst::kIdMovups;
364 :
365 0 : OperandSignature signature = Reg::signatureOfVecBySize(srcSize);
366 : dst.setSignature(signature);
367 0 : if (src.isReg())
368 : src.setSignature(signature);
369 : break;
370 : }
371 : }
372 :
373 : return DebugUtils::errored(kErrorInvalidState);
374 : }
375 :
376 0 : if (src.isMem())
377 0 : src.as<Mem>().setSize(srcSize);
378 :
379 0 : _emitter->setInlineComment(comment);
380 0 : return _emitter->emit(instId, dst, src);
381 : }
382 :
383 0 : Error EmitHelper::emitRegSwap(
384 : const BaseReg& a,
385 : const BaseReg& b, const char* comment) {
386 :
387 0 : if (a.isGp() && b.isGp()) {
388 0 : _emitter->setInlineComment(comment);
389 0 : return _emitter->emit(Inst::kIdXchg, a, b);
390 : }
391 : else
392 : return DebugUtils::errored(kErrorInvalidState);
393 : }
394 :
395 : // x86::EmitHelper - Emit Prolog & Epilog
396 : // ======================================
397 :
398 0 : static inline void X86Internal_setupSaveRestoreInfo(RegGroup group, const FuncFrame& frame, Reg& xReg, uint32_t& xInst, uint32_t& xSize) noexcept {
399 0 : switch (group) {
400 0 : case RegGroup::kVec:
401 0 : xReg = xmm(0);
402 0 : xInst = getXmmMovInst(frame);
403 0 : xSize = xReg.size();
404 0 : break;
405 0 : case RegGroup::kX86_K:
406 0 : xReg = k(0);
407 0 : xInst = Inst::kIdKmovq;
408 0 : xSize = xReg.size();
409 0 : break;
410 0 : case RegGroup::kX86_MM:
411 0 : xReg = mm(0);
412 0 : xInst = Inst::kIdMovq;
413 0 : xSize = xReg.size();
414 0 : break;
415 : default:
416 : break;
417 : }
418 0 : }
419 :
420 27492 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
421 27492 : Emitter* emitter = _emitter->as<Emitter>();
422 : uint32_t gpSaved = frame.savedRegs(RegGroup::kGp);
423 :
424 : Gp zsp = emitter->zsp(); // ESP|RSP register.
425 : Gp zbp = emitter->zbp(); // EBP|RBP register.
426 : Gp gpReg = zsp; // General purpose register (temporary).
427 : Gp saReg = zsp; // Stack-arguments base pointer.
428 :
429 : // Emit: 'push zbp'
430 : // 'mov zbp, zsp'.
431 27492 : if (frame.hasPreservedFP()) {
432 0 : gpSaved &= ~Support::bitMask(Gp::kIdBp);
433 0 : ASMJIT_PROPAGATE(emitter->push(zbp));
434 0 : ASMJIT_PROPAGATE(emitter->mov(zbp, zsp));
435 : }
436 :
437 : // Emit: 'push gp' sequence.
438 : {
439 : Support::BitWordIterator<RegMask> it(gpSaved);
440 27492 : while (it.hasNext()) {
441 : gpReg.setId(it.next());
442 0 : ASMJIT_PROPAGATE(emitter->push(gpReg));
443 : }
444 : }
445 :
446 : // Emit: 'mov saReg, zsp'.
447 : uint32_t saRegId = frame.saRegId();
448 27492 : if (saRegId != BaseReg::kIdBad && saRegId != Gp::kIdSp) {
449 : saReg.setId(saRegId);
450 0 : if (frame.hasPreservedFP()) {
451 0 : if (saRegId != Gp::kIdBp)
452 0 : ASMJIT_PROPAGATE(emitter->mov(saReg, zbp));
453 : }
454 : else {
455 0 : ASMJIT_PROPAGATE(emitter->mov(saReg, zsp));
456 : }
457 : }
458 :
459 : // Emit: 'and zsp, StackAlignment'.
460 27492 : if (frame.hasDynamicAlignment()) {
461 0 : ASMJIT_PROPAGATE(emitter->and_(zsp, -int32_t(frame.finalStackAlignment())));
462 : }
463 :
464 : // Emit: 'sub zsp, StackAdjustment'.
465 27492 : if (frame.hasStackAdjustment()) {
466 4990 : ASMJIT_PROPAGATE(emitter->sub(zsp, frame.stackAdjustment()));
467 : }
468 :
469 : // Emit: 'mov [zsp + DAOffset], saReg'.
470 27492 : if (frame.hasDynamicAlignment() && frame.hasDAOffset()) {
471 0 : Mem saMem = ptr(zsp, int32_t(frame.daOffset()));
472 0 : ASMJIT_PROPAGATE(emitter->mov(saMem, saReg));
473 : }
474 :
475 : // Emit 'movxxx [zsp + X], {[x|y|z]mm, k}'.
476 : {
477 27492 : Reg xReg;
478 27492 : Mem xBase = ptr(zsp, int32_t(frame.extraRegSaveOffset()));
479 :
480 : uint32_t xInst;
481 : uint32_t xSize;
482 :
483 109968 : for (RegGroup group : Support::EnumValues<RegGroup, RegGroup(1), RegGroup::kMaxVirt>{}) {
484 : Support::BitWordIterator<RegMask> it(frame.savedRegs(group));
485 82476 : if (it.hasNext()) {
486 0 : X86Internal_setupSaveRestoreInfo(group, frame, xReg, xInst, xSize);
487 : do {
488 : xReg.setId(it.next());
489 0 : ASMJIT_PROPAGATE(emitter->emit(xInst, xBase, xReg));
490 0 : xBase.addOffsetLo32(int32_t(xSize));
491 0 : } while (it.hasNext());
492 : }
493 : }
494 : }
495 :
496 27492 : return kErrorOk;
497 : }
498 :
499 27492 : ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
500 27492 : Emitter* emitter = _emitter->as<Emitter>();
501 :
502 : uint32_t i;
503 : uint32_t regId;
504 :
505 27492 : uint32_t registerSize = emitter->registerSize();
506 : uint32_t gpSaved = frame.savedRegs(RegGroup::kGp);
507 :
508 : Gp zsp = emitter->zsp(); // ESP|RSP register.
509 : Gp zbp = emitter->zbp(); // EBP|RBP register.
510 : Gp gpReg = emitter->zsp(); // General purpose register (temporary).
511 :
512 : // Don't emit 'pop zbp' in the pop sequence, this case is handled separately.
513 27492 : if (frame.hasPreservedFP())
514 0 : gpSaved &= ~Support::bitMask(Gp::kIdBp);
515 :
516 : // Emit 'movxxx {[x|y|z]mm, k}, [zsp + X]'.
517 : {
518 27492 : Reg xReg;
519 27492 : Mem xBase = ptr(zsp, int32_t(frame.extraRegSaveOffset()));
520 :
521 : uint32_t xInst;
522 : uint32_t xSize;
523 :
524 109968 : for (RegGroup group : Support::EnumValues<RegGroup, RegGroup(1), RegGroup::kMaxVirt>{}) {
525 : Support::BitWordIterator<RegMask> it(frame.savedRegs(group));
526 82476 : if (it.hasNext()) {
527 0 : X86Internal_setupSaveRestoreInfo(group, frame, xReg, xInst, xSize);
528 : do {
529 : xReg.setId(it.next());
530 0 : ASMJIT_PROPAGATE(emitter->emit(xInst, xReg, xBase));
531 0 : xBase.addOffsetLo32(int32_t(xSize));
532 0 : } while (it.hasNext());
533 : }
534 : }
535 : }
536 :
537 : // Emit 'emms' and/or 'vzeroupper'.
538 27492 : if (frame.hasMmxCleanup()) ASMJIT_PROPAGATE(emitter->emms());
539 27492 : if (frame.hasAvxCleanup()) ASMJIT_PROPAGATE(emitter->vzeroupper());
540 :
541 27492 : if (frame.hasPreservedFP()) {
542 : // Emit 'mov zsp, zbp' or 'lea zsp, [zbp - x]'
543 0 : int32_t count = int32_t(frame.pushPopSaveSize() - registerSize);
544 0 : if (!count)
545 0 : ASMJIT_PROPAGATE(emitter->mov(zsp, zbp));
546 : else
547 0 : ASMJIT_PROPAGATE(emitter->lea(zsp, ptr(zbp, -count)));
548 : }
549 : else {
550 27492 : if (frame.hasDynamicAlignment() && frame.hasDAOffset()) {
551 : // Emit 'mov zsp, [zsp + DsaSlot]'.
552 0 : Mem saMem = ptr(zsp, int32_t(frame.daOffset()));
553 0 : ASMJIT_PROPAGATE(emitter->mov(zsp, saMem));
554 : }
555 27492 : else if (frame.hasStackAdjustment()) {
556 : // Emit 'add zsp, StackAdjustment'.
557 4990 : ASMJIT_PROPAGATE(emitter->add(zsp, int32_t(frame.stackAdjustment())));
558 : }
559 : }
560 :
561 : // Emit 'pop gp' sequence.
562 27492 : if (gpSaved) {
563 : i = gpSaved;
564 : regId = 16;
565 :
566 : do {
567 0 : regId--;
568 0 : if (i & 0x8000) {
569 : gpReg.setId(regId);
570 0 : ASMJIT_PROPAGATE(emitter->pop(gpReg));
571 : }
572 0 : i <<= 1;
573 0 : } while (regId != 0);
574 : }
575 :
576 : // Emit 'pop zbp'.
577 27492 : if (frame.hasPreservedFP())
578 0 : ASMJIT_PROPAGATE(emitter->pop(zbp));
579 :
580 : // Emit 'ret' or 'ret x'.
581 27492 : if (frame.hasCalleeStackCleanup())
582 0 : ASMJIT_PROPAGATE(emitter->emit(Inst::kIdRet, int(frame.calleeStackCleanup())));
583 : else
584 27492 : ASMJIT_PROPAGATE(emitter->emit(Inst::kIdRet));
585 :
586 : return kErrorOk;
587 : }
588 :
589 27492 : static Error ASMJIT_CDECL Emitter_emitProlog(BaseEmitter* emitter, const FuncFrame& frame) {
590 : EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
591 27492 : return emitHelper.emitProlog(frame);
592 : }
593 :
594 27492 : static Error ASMJIT_CDECL Emitter_emitEpilog(BaseEmitter* emitter, const FuncFrame& frame) {
595 : EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
596 27492 : return emitHelper.emitEpilog(frame);
597 : }
598 :
599 0 : static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) {
600 : EmitHelper emitHelper(emitter, frame.isAvxEnabled(), frame.isAvx512Enabled());
601 0 : return emitHelper.emitArgsAssignment(frame, args);
602 : }
603 :
604 54984 : void assignEmitterFuncs(BaseEmitter* emitter) {
605 54984 : emitter->_funcs.emitProlog = Emitter_emitProlog;
606 54984 : emitter->_funcs.emitEpilog = Emitter_emitEpilog;
607 54984 : emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
608 :
609 : #ifndef ASMJIT_NO_LOGGING
610 54984 : emitter->_funcs.formatInstruction = FormatterInternal::formatInstruction;
611 : #endif
612 :
613 : #ifndef ASMJIT_NO_VALIDATION
614 54984 : emitter->_funcs.validate = InstInternal::validate;
615 : #endif
616 54984 : }
617 :
618 : ASMJIT_END_SUB_NAMESPACE
619 :
620 : #endif // !ASMJIT_NO_X86
621 :
622 : #endif // __PLUMED_HAS_ASMJIT
|