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 : #ifndef ASMJIT_NO_COMPILER
9 :
10 : #include "assembler.h"
11 : #include "compiler.h"
12 : #include "cpuinfo.h"
13 : #include "logger.h"
14 : #include "rapass_p.h"
15 : #include "rastack_p.h"
16 : #include "support.h"
17 : #include "type.h"
18 :
19 : ASMJIT_BEGIN_NAMESPACE
20 :
21 : // GlobalConstPoolPass
22 : // ===================
23 :
24 : class GlobalConstPoolPass : public Pass {
25 : public:
26 : typedef Pass Base;
27 : public:
28 : ASMJIT_NONCOPYABLE(GlobalConstPoolPass)
29 :
30 27492 : GlobalConstPoolPass() noexcept : Pass("GlobalConstPoolPass") {}
31 :
32 27492 : Error run(Zone* zone, Logger* logger) override {
33 : DebugUtils::unused(zone, logger);
34 :
35 : // Flush the global constant pool.
36 27492 : BaseCompiler* compiler = static_cast<BaseCompiler*>(_cb);
37 27492 : ConstPoolNode* globalConstPool = compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)];
38 :
39 27492 : if (globalConstPool) {
40 0 : compiler->addAfter(globalConstPool, compiler->lastNode());
41 0 : compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
42 : }
43 :
44 27492 : return kErrorOk;
45 : }
46 : };
47 :
48 : // BaseCompiler - Construction & Destruction
49 : // =========================================
50 :
51 27492 : BaseCompiler::BaseCompiler() noexcept
52 : : BaseBuilder(),
53 27492 : _func(nullptr),
54 27492 : _vRegZone(4096 - Zone::kBlockOverhead),
55 : _vRegArray(),
56 27492 : _constPools { nullptr, nullptr } {
57 27492 : _emitterType = EmitterType::kCompiler;
58 27492 : _validationFlags = ValidationFlags::kEnableVirtRegs;
59 27492 : }
60 27492 : BaseCompiler::~BaseCompiler() noexcept {}
61 :
62 : // BaseCompiler - Function Management
63 : // ==================================
64 :
65 27492 : Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature) {
66 27492 : *out = nullptr;
67 :
68 : // Create FuncNode together with all the required surrounding nodes.
69 : FuncNode* funcNode;
70 27492 : ASMJIT_PROPAGATE(_newNodeT<FuncNode>(&funcNode));
71 27492 : ASMJIT_PROPAGATE(newLabelNode(&funcNode->_exitNode));
72 27492 : ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelType::kFuncEnd));
73 :
74 : // Initialize the function's detail info.
75 27492 : Error err = funcNode->detail().init(signature, environment());
76 27492 : if (ASMJIT_UNLIKELY(err))
77 0 : return reportError(err);
78 :
79 : // If the Target guarantees greater stack alignment than required by the calling convention
80 : // then override it as we can prevent having to perform dynamic stack alignment
81 27492 : uint32_t environmentStackAlignment = _environment.stackAlignment();
82 :
83 27492 : if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment)
84 : funcNode->_funcDetail._callConv.setNaturalStackAlignment(environmentStackAlignment);
85 :
86 : // Initialize the function frame.
87 27492 : err = funcNode->_frame.init(funcNode->_funcDetail);
88 27492 : if (ASMJIT_UNLIKELY(err))
89 0 : return reportError(err);
90 :
91 : // Allocate space for function arguments.
92 27492 : funcNode->_args = nullptr;
93 27492 : if (funcNode->argCount() != 0) {
94 0 : funcNode->_args = _allocator.allocT<FuncNode::ArgPack>(funcNode->argCount() * sizeof(FuncNode::ArgPack));
95 0 : if (ASMJIT_UNLIKELY(!funcNode->_args))
96 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
97 0 : memset(funcNode->_args, 0, funcNode->argCount() * sizeof(FuncNode::ArgPack));
98 : }
99 :
100 27492 : ASMJIT_PROPAGATE(registerLabelNode(funcNode));
101 :
102 27492 : *out = funcNode;
103 27492 : return kErrorOk;
104 : }
105 :
106 27492 : Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature) {
107 27492 : ASMJIT_PROPAGATE(newFuncNode(out, signature));
108 27492 : ASMJIT_ASSUME(*out != nullptr);
109 :
110 27492 : addFunc(*out);
111 27492 : return kErrorOk;
112 : }
113 :
114 27492 : Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
115 27492 : uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u;
116 : FuncRetNode* node;
117 :
118 27492 : ASMJIT_PROPAGATE(_newNodeT<FuncRetNode>(&node));
119 27492 : ASMJIT_ASSUME(node != nullptr);
120 :
121 : node->setOpCount(opCount);
122 : node->setOp(0, o0);
123 : node->setOp(1, o1);
124 : node->resetOpRange(2, node->opCapacity());
125 :
126 27492 : *out = node;
127 27492 : return kErrorOk;
128 : }
129 :
130 27492 : Error BaseCompiler::addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
131 27492 : ASMJIT_PROPAGATE(newFuncRetNode(out, o0, o1));
132 27492 : addNode(*out);
133 27492 : return kErrorOk;
134 : }
135 :
136 27492 : FuncNode* BaseCompiler::addFunc(FuncNode* func) {
137 27492 : _func = func;
138 :
139 27492 : addNode(func); // Function node.
140 : BaseNode* prev = cursor(); // {CURSOR}.
141 27492 : addNode(func->exitNode()); // Function exit label.
142 27492 : addNode(func->endNode()); // Function end sentinel.
143 :
144 : _setCursor(prev);
145 27492 : return func;
146 : }
147 :
148 27492 : Error BaseCompiler::endFunc() {
149 27492 : FuncNode* func = _func;
150 :
151 27492 : if (ASMJIT_UNLIKELY(!func))
152 0 : return reportError(DebugUtils::errored(kErrorInvalidState));
153 :
154 : // Add the local constant pool at the end of the function (if exists).
155 27492 : ConstPoolNode* localConstPool = _constPools[uint32_t(ConstPoolScope::kLocal)];
156 27492 : if (localConstPool) {
157 0 : setCursor(func->endNode()->prev());
158 0 : addNode(localConstPool);
159 0 : _constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
160 : }
161 :
162 : // Mark as finished.
163 27492 : _func = nullptr;
164 :
165 : SentinelNode* end = func->endNode();
166 27492 : setCursor(end);
167 :
168 27492 : return kErrorOk;
169 : }
170 :
171 : // BaseCompiler - Function Invocation
172 : // ==================================
173 :
174 9639 : Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
175 : InvokeNode* node;
176 9639 : ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, InstOptions::kNone));
177 :
178 9639 : node->setOpCount(1);
179 : node->setOp(0, o0);
180 : node->resetOpRange(1, node->opCapacity());
181 :
182 9639 : Error err = node->detail().init(signature, environment());
183 9639 : if (ASMJIT_UNLIKELY(err))
184 0 : return reportError(err);
185 :
186 : // Skip the allocation if there are no arguments.
187 : uint32_t argCount = signature.argCount();
188 9639 : if (argCount) {
189 9639 : node->_args = static_cast<InvokeNode::OperandPack*>(_allocator.alloc(argCount * sizeof(InvokeNode::OperandPack)));
190 9639 : if (!node->_args)
191 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
192 : memset(node->_args, 0, argCount * sizeof(InvokeNode::OperandPack));
193 : }
194 :
195 9639 : *out = node;
196 9639 : return kErrorOk;
197 : }
198 :
199 9639 : Error BaseCompiler::addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
200 9639 : ASMJIT_PROPAGATE(newInvokeNode(out, instId, o0, signature));
201 9639 : addNode(*out);
202 9639 : return kErrorOk;
203 : }
204 :
205 : // BaseCompiler - Virtual Registers
206 : // ================================
207 :
208 273777 : static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
209 273777 : uint32_t index = unsigned(Operand::virtIdToIndex(vReg->_id));
210 :
211 : char buf[64];
212 : int size = snprintf(buf, ASMJIT_ARRAY_SIZE(buf), "%%%u", unsigned(index));
213 :
214 : ASMJIT_ASSERT(size > 0 && size < int(ASMJIT_ARRAY_SIZE(buf)));
215 273777 : vReg->_name.setData(&self->_dataZone, buf, unsigned(size));
216 273777 : }
217 :
218 273777 : Error BaseCompiler::newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name) {
219 273777 : *out = nullptr;
220 : uint32_t index = _vRegArray.size();
221 :
222 273777 : if (ASMJIT_UNLIKELY(index >= uint32_t(Operand::kVirtIdCount)))
223 0 : return reportError(DebugUtils::errored(kErrorTooManyVirtRegs));
224 :
225 273777 : if (ASMJIT_UNLIKELY(_vRegArray.willGrow(&_allocator) != kErrorOk))
226 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
227 :
228 273777 : VirtReg* vReg = _vRegZone.allocZeroedT<VirtReg>();
229 273777 : if (ASMJIT_UNLIKELY(!vReg))
230 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
231 :
232 : uint32_t size = TypeUtils::sizeOf(typeId);
233 : uint32_t alignment = Support::min<uint32_t>(size, 64);
234 :
235 : vReg = new(vReg) VirtReg(signature, Operand::indexToVirtId(index), size, alignment, typeId);
236 :
237 : #ifndef ASMJIT_NO_LOGGING
238 273777 : if (name && name[0] != '\0')
239 0 : vReg->_name.setData(&_dataZone, name, SIZE_MAX);
240 : else
241 273777 : BaseCompiler_assignGenericName(this, vReg);
242 : #else
243 : DebugUtils::unused(name);
244 : #endif
245 :
246 : _vRegArray.appendUnsafe(vReg);
247 273777 : *out = vReg;
248 :
249 273777 : return kErrorOk;
250 : }
251 :
252 273777 : Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) {
253 : OperandSignature regSignature;
254 : out->reset();
255 :
256 273777 : Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
257 273777 : if (ASMJIT_UNLIKELY(err))
258 0 : return reportError(err);
259 :
260 : VirtReg* vReg;
261 273777 : ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name));
262 273777 : ASMJIT_ASSUME(vReg != nullptr);
263 :
264 : out->_initReg(regSignature, vReg->id());
265 273777 : return kErrorOk;
266 : }
267 :
268 0 : Error BaseCompiler::_newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...) {
269 : va_list ap;
270 : StringTmp<256> sb;
271 :
272 0 : va_start(ap, fmt);
273 : sb.appendVFormat(fmt, ap);
274 0 : va_end(ap);
275 :
276 0 : return _newReg(out, typeId, sb.data());
277 : }
278 :
279 0 : Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) {
280 : out->reset();
281 :
282 : OperandSignature regSignature;
283 : TypeId typeId;
284 :
285 0 : if (isVirtRegValid(ref)) {
286 : VirtReg* vRef = virtRegByReg(ref);
287 0 : typeId = vRef->typeId();
288 :
289 : // NOTE: It's possible to cast one register type to another if it's the same register group. However, VirtReg
290 : // always contains the TypeId that was used to create the register. This means that in some cases we may end
291 : // up having different size of `ref` and `vRef`. In such case we adjust the TypeId to match the `ref` register
292 : // type instead of the original register type, which should be the expected behavior.
293 : uint32_t typeSize = TypeUtils::sizeOf(typeId);
294 : uint32_t refSize = ref.size();
295 :
296 0 : if (typeSize != refSize) {
297 : if (TypeUtils::isInt(typeId)) {
298 : // GP register - change TypeId to match `ref`, but keep sign of `vRef`.
299 0 : switch (refSize) {
300 0 : case 1: typeId = TypeId(uint32_t(TypeId::kInt8 ) | (uint32_t(typeId) & 1)); break;
301 0 : case 2: typeId = TypeId(uint32_t(TypeId::kInt16) | (uint32_t(typeId) & 1)); break;
302 0 : case 4: typeId = TypeId(uint32_t(TypeId::kInt32) | (uint32_t(typeId) & 1)); break;
303 0 : case 8: typeId = TypeId(uint32_t(TypeId::kInt64) | (uint32_t(typeId) & 1)); break;
304 0 : default: typeId = TypeId::kVoid; break;
305 : }
306 : }
307 : else if (TypeUtils::isMmx(typeId)) {
308 : // MMX register - always use 64-bit.
309 0 : typeId = TypeId::kMmx64;
310 : }
311 : else if (TypeUtils::isMask(typeId)) {
312 : // Mask register - change TypeId to match `ref` size.
313 0 : switch (refSize) {
314 0 : case 1: typeId = TypeId::kMask8; break;
315 0 : case 2: typeId = TypeId::kMask16; break;
316 0 : case 4: typeId = TypeId::kMask32; break;
317 0 : case 8: typeId = TypeId::kMask64; break;
318 0 : default: typeId = TypeId::kVoid; break;
319 : }
320 : }
321 : else {
322 : // Vector register - change TypeId to match `ref` size, keep vector metadata.
323 : TypeId scalarTypeId = TypeUtils::scalarOf(typeId);
324 0 : switch (refSize) {
325 0 : case 16: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec128Start); break;
326 0 : case 32: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec256Start); break;
327 0 : case 64: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec512Start); break;
328 0 : default: typeId = TypeId::kVoid; break;
329 : }
330 : }
331 :
332 0 : if (typeId == TypeId::kVoid)
333 0 : return reportError(DebugUtils::errored(kErrorInvalidState));
334 : }
335 : }
336 : else {
337 0 : typeId = ArchTraits::byArch(arch()).regTypeToTypeId(ref.type());
338 : }
339 :
340 0 : Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
341 0 : if (ASMJIT_UNLIKELY(err))
342 0 : return reportError(err);
343 :
344 : VirtReg* vReg;
345 0 : ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name));
346 0 : ASMJIT_ASSUME(vReg != nullptr);
347 :
348 : out->_initReg(regSignature, vReg->id());
349 0 : return kErrorOk;
350 : }
351 :
352 0 : Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...) {
353 : va_list ap;
354 : StringTmp<256> sb;
355 :
356 0 : va_start(ap, fmt);
357 : sb.appendVFormat(fmt, ap);
358 0 : va_end(ap);
359 :
360 0 : return _newReg(out, ref, sb.data());
361 : }
362 :
363 0 : Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) {
364 : out->reset();
365 :
366 0 : if (size == 0)
367 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
368 :
369 : if (alignment == 0)
370 : alignment = 1;
371 :
372 : if (!Support::isPowerOf2(alignment))
373 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
374 :
375 0 : if (alignment > 64)
376 : alignment = 64;
377 :
378 : VirtReg* vReg;
379 0 : ASMJIT_PROPAGATE(newVirtReg(&vReg, TypeId::kVoid, OperandSignature{0}, name));
380 0 : ASMJIT_ASSUME(vReg != nullptr);
381 :
382 0 : vReg->_virtSize = size;
383 0 : vReg->_isStack = true;
384 0 : vReg->_alignment = uint8_t(alignment);
385 :
386 : // Set the memory operand to GPD/GPQ and its id to VirtReg.
387 0 : *out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
388 : OperandSignature::fromMemBaseType(_gpSignature.regType()) |
389 : OperandSignature::fromBits(OperandSignature::kMemRegHomeFlag),
390 : vReg->id(), 0, 0);
391 0 : return kErrorOk;
392 : }
393 :
394 0 : Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) {
395 0 : if (!isVirtIdValid(virtId))
396 : return DebugUtils::errored(kErrorInvalidVirtId);
397 :
398 0 : if (newAlignment && !Support::isPowerOf2(newAlignment))
399 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
400 :
401 0 : if (newAlignment > 64)
402 : newAlignment = 64;
403 :
404 : VirtReg* vReg = virtRegById(virtId);
405 0 : if (newSize)
406 0 : vReg->_virtSize = newSize;
407 :
408 0 : if (newAlignment)
409 0 : vReg->_alignment = uint8_t(newAlignment);
410 :
411 : // This is required if the RAPass is already running. There is a chance that a stack-slot has been already
412 : // allocated and in that case it has to be updated as well, otherwise we would allocate wrong amount of memory.
413 0 : RAWorkReg* workReg = vReg->_workReg;
414 0 : if (workReg && workReg->_stackSlot) {
415 0 : workReg->_stackSlot->_size = vReg->_virtSize;
416 0 : workReg->_stackSlot->_alignment = vReg->_alignment;
417 : }
418 :
419 : return kErrorOk;
420 : }
421 :
422 0 : Error BaseCompiler::_newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size) {
423 : out->reset();
424 :
425 0 : if (uint32_t(scope) > 1)
426 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
427 :
428 0 : if (!_constPools[uint32_t(scope)])
429 0 : ASMJIT_PROPAGATE(newConstPoolNode(&_constPools[uint32_t(scope)]));
430 :
431 0 : ConstPoolNode* pool = _constPools[uint32_t(scope)];
432 : size_t off;
433 : Error err = pool->add(data, size, off);
434 :
435 0 : if (ASMJIT_UNLIKELY(err))
436 0 : return reportError(err);
437 :
438 0 : *out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
439 : OperandSignature::fromMemBaseType(RegType::kLabelTag) |
440 0 : OperandSignature::fromSize(uint32_t(size)),
441 : pool->labelId(), 0, int32_t(off));
442 0 : return kErrorOk;
443 : }
444 :
445 0 : void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
446 0 : if (!reg.isVirtReg()) return;
447 :
448 : VirtReg* vReg = virtRegById(reg.id());
449 0 : if (!vReg) return;
450 :
451 0 : if (fmt && fmt[0] != '\0') {
452 : char buf[128];
453 : va_list ap;
454 :
455 0 : va_start(ap, fmt);
456 : vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
457 0 : va_end(ap);
458 :
459 0 : vReg->_name.setData(&_dataZone, buf, SIZE_MAX);
460 0 : }
461 : else {
462 0 : BaseCompiler_assignGenericName(this, vReg);
463 : }
464 : }
465 :
466 : // BaseCompiler - Jump Annotations
467 : // ===============================
468 :
469 0 : Error BaseCompiler::newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation) {
470 0 : JumpNode* node = _allocator.allocT<JumpNode>();
471 : uint32_t opCount = 1;
472 :
473 0 : *out = node;
474 0 : if (ASMJIT_UNLIKELY(!node))
475 0 : return reportError(DebugUtils::errored(kErrorOutOfMemory));
476 :
477 : node = new(node) JumpNode(this, instId, instOptions, opCount, annotation);
478 : node->setOp(0, o0);
479 : node->resetOpRange(opCount, JumpNode::kBaseOpCapacity);
480 :
481 : return kErrorOk;
482 : }
483 :
484 0 : Error BaseCompiler::emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation) {
485 : InstOptions options = instOptions() | forcedInstOptions();
486 0 : RegOnly extra = extraReg();
487 : const char* comment = inlineComment();
488 :
489 : resetInstOptions();
490 : resetInlineComment();
491 : resetExtraReg();
492 :
493 : JumpNode* node;
494 0 : ASMJIT_PROPAGATE(newJumpNode(&node, instId, options, o0, annotation));
495 :
496 0 : node->setExtraReg(extra);
497 0 : if (comment)
498 0 : node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true)));
499 :
500 0 : addNode(node);
501 0 : return kErrorOk;
502 : }
503 :
504 0 : JumpAnnotation* BaseCompiler::newJumpAnnotation() {
505 0 : if (_jumpAnnotations.grow(&_allocator, 1) != kErrorOk) {
506 0 : reportError(DebugUtils::errored(kErrorOutOfMemory));
507 0 : return nullptr;
508 : }
509 :
510 0 : uint32_t id = _jumpAnnotations.size();
511 0 : JumpAnnotation* jumpAnnotation = _allocator.newT<JumpAnnotation>(this, id);
512 :
513 0 : if (!jumpAnnotation) {
514 0 : reportError(DebugUtils::errored(kErrorOutOfMemory));
515 0 : return nullptr;
516 : }
517 :
518 : _jumpAnnotations.appendUnsafe(jumpAnnotation);
519 0 : return jumpAnnotation;
520 : }
521 :
522 : // BaseCompiler - Events
523 : // =====================
524 :
525 27492 : Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
526 27492 : ASMJIT_PROPAGATE(Base::onAttach(code));
527 :
528 : const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
529 27492 : RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
530 27492 : _gpSignature = archTraits.regTypeToSignature(nativeRegType);
531 :
532 27492 : Error err = addPassT<GlobalConstPoolPass>();
533 27492 : if (ASMJIT_UNLIKELY(err)) {
534 0 : onDetach(code);
535 0 : return err;
536 : }
537 :
538 : return kErrorOk;
539 : }
540 :
541 0 : Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
542 0 : _func = nullptr;
543 0 : _constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
544 0 : _constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
545 :
546 : _vRegArray.reset();
547 0 : _vRegZone.reset();
548 :
549 0 : return Base::onDetach(code);
550 : }
551 :
552 : // FuncPass - Construction & Destruction
553 : // =====================================
554 :
555 27492 : FuncPass::FuncPass(const char* name) noexcept
556 27492 : : Pass(name) {}
557 :
558 : // FuncPass - Run
559 : // ==============
560 :
561 27492 : Error FuncPass::run(Zone* zone, Logger* logger) {
562 : BaseNode* node = cb()->firstNode();
563 27492 : if (!node) return kErrorOk;
564 :
565 : do {
566 : if (node->type() == NodeType::kFunc) {
567 : FuncNode* func = node->as<FuncNode>();
568 : node = func->endNode();
569 27492 : ASMJIT_PROPAGATE(runOnFunction(zone, logger, func));
570 : }
571 :
572 : // Find a function by skipping all nodes that are not `NodeType::kFunc`.
573 : do {
574 : node = node->next();
575 82476 : } while (node && node->type() != NodeType::kFunc);
576 54984 : } while (node);
577 :
578 : return kErrorOk;
579 : }
580 :
581 : ASMJIT_END_NAMESPACE
582 :
583 : #endif // !ASMJIT_NO_COMPILER
584 :
585 : #endif // __PLUMED_HAS_ASMJIT
|