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 "formatter.h"
11 : #include "ralocal_p.h"
12 : #include "rapass_p.h"
13 : #include "support.h"
14 : #include "type.h"
15 : #include "zonestack.h"
16 :
17 : ASMJIT_BEGIN_NAMESPACE
18 :
19 : // RABlock - Control Flow
20 : // ======================
21 :
22 27492 : Error RABlock::appendSuccessor(RABlock* successor) noexcept {
23 27492 : RABlock* predecessor = this;
24 :
25 27492 : if (predecessor->hasSuccessor(successor))
26 : return kErrorOk;
27 :
28 27492 : ASMJIT_PROPAGATE(successor->_predecessors.willGrow(allocator()));
29 27492 : ASMJIT_PROPAGATE(predecessor->_successors.willGrow(allocator()));
30 :
31 : predecessor->_successors.appendUnsafe(successor);
32 : successor->_predecessors.appendUnsafe(predecessor);
33 :
34 27492 : return kErrorOk;
35 : }
36 :
37 0 : Error RABlock::prependSuccessor(RABlock* successor) noexcept {
38 0 : RABlock* predecessor = this;
39 :
40 0 : if (predecessor->hasSuccessor(successor))
41 : return kErrorOk;
42 :
43 0 : ASMJIT_PROPAGATE(successor->_predecessors.willGrow(allocator()));
44 0 : ASMJIT_PROPAGATE(predecessor->_successors.willGrow(allocator()));
45 :
46 : predecessor->_successors.prependUnsafe(successor);
47 : successor->_predecessors.prependUnsafe(predecessor);
48 :
49 0 : return kErrorOk;
50 : }
51 :
52 : // BaseRAPass - Construction & Destruction
53 : // =======================================
54 :
55 632316 : BaseRAPass::BaseRAPass() noexcept : FuncPass("BaseRAPass") {}
56 27492 : BaseRAPass::~BaseRAPass() noexcept {}
57 :
58 : // BaseRAPass - RunOnFunction
59 : // ==========================
60 :
61 54984 : static void BaseRAPass_reset(BaseRAPass* self, FuncDetail* funcDetail) noexcept {
62 : ZoneAllocator* allocator = self->allocator();
63 :
64 : self->_blocks.reset();
65 : self->_exits.reset();
66 : self->_pov.reset();
67 : self->_workRegs.reset();
68 54984 : self->_instructionCount = 0;
69 54984 : self->_createdBlockCount = 0;
70 :
71 : self->_sharedAssignments.reset();
72 54984 : self->_lastTimestamp = 0;
73 :
74 54984 : self->_archTraits = nullptr;
75 : self->_physRegIndex.reset();
76 : self->_physRegCount.reset();
77 54984 : self->_physRegTotal = 0;
78 : self->_scratchRegIndexes.fill(BaseReg::kIdBad);
79 :
80 : self->_availableRegs.reset();
81 : self->_availableRegCount.reset();
82 : self->_clobberedRegs.reset();
83 :
84 : self->_workRegs.reset();
85 : self->_workRegsOfGroup.forEach([](RAWorkRegs& regs) { regs.reset(); });
86 : self->_strategy.forEach([](RAStrategy& strategy) { strategy.reset(); });
87 : self->_globalLiveSpans.fill(nullptr);
88 : self->_globalMaxLiveCount.reset();
89 : self->_temporaryMem.reset();
90 :
91 : self->_stackAllocator.reset(allocator);
92 54984 : self->_argsAssignment.reset(funcDetail);
93 54984 : self->_numStackArgsToStackSlots = 0;
94 54984 : self->_maxWorkRegNameSize = 0;
95 54984 : }
96 :
97 27492 : static void BaseRAPass_resetVirtRegData(BaseRAPass* self) noexcept {
98 298806 : for (RAWorkReg* wReg : self->_workRegs) {
99 : VirtReg* vReg = wReg->virtReg();
100 :
101 : // Update the information regarding the stack of the virtual register.
102 271314 : if (wReg->hasStackSlot()) {
103 : RAStackSlot* slot = wReg->stackSlot();
104 : vReg->assignStackSlot(slot->offset());
105 : }
106 :
107 : // Reset work reg association so it cannot be used by accident (RAWorkReg data will be destroyed).
108 271314 : vReg->_workReg = nullptr;
109 : }
110 27492 : }
111 :
112 27492 : Error BaseRAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) {
113 27492 : _allocator.reset(zone);
114 :
115 : #ifndef ASMJIT_NO_LOGGING
116 27492 : _logger = logger;
117 27492 : _formatOptions.reset();
118 27492 : _diagnosticOptions = DiagnosticOptions::kNone;
119 :
120 27492 : if (logger) {
121 0 : _formatOptions = logger->options();
122 0 : _diagnosticOptions = _cb->diagnosticOptions();
123 : }
124 : #else
125 : DebugUtils::unused(logger);
126 : #endif
127 :
128 : // Initialize all core structures to use `zone` and `func`.
129 : BaseNode* end = func->endNode();
130 27492 : _func = func;
131 27492 : _stop = end->next();
132 27492 : _extraBlock = end;
133 :
134 27492 : BaseRAPass_reset(this, &_func->_funcDetail);
135 :
136 : // Initialize architecture-specific members.
137 27492 : onInit();
138 :
139 : // Perform all allocation steps required.
140 27492 : Error err = onPerformAllSteps();
141 :
142 : // Must be called regardless of the allocation status.
143 27492 : onDone();
144 :
145 : // Reset possible connections introduced by the register allocator.
146 27492 : BaseRAPass_resetVirtRegData(this);
147 :
148 : // Reset all core structures and everything that depends on the passed `Zone`.
149 27492 : BaseRAPass_reset(this, nullptr);
150 27492 : _allocator.reset(nullptr);
151 :
152 : #ifndef ASMJIT_NO_LOGGING
153 27492 : _logger = nullptr;
154 27492 : _formatOptions.reset();
155 27492 : _diagnosticOptions = DiagnosticOptions::kNone;
156 : #endif
157 :
158 27492 : _func = nullptr;
159 27492 : _stop = nullptr;
160 27492 : _extraBlock = nullptr;
161 :
162 : // Reset `Zone` as nothing should persist between `runOnFunction()` calls.
163 27492 : zone->reset();
164 :
165 : // We alter the compiler cursor, because it doesn't make sense to reference it after the compilation - some
166 : // nodes may disappear and the old cursor can go out anyway.
167 : cc()->_setCursor(cc()->lastNode());
168 :
169 27492 : return err;
170 : }
171 :
172 27492 : Error BaseRAPass::onPerformAllSteps() noexcept {
173 27492 : ASMJIT_PROPAGATE(buildCFG());
174 27492 : ASMJIT_PROPAGATE(buildCFGViews());
175 27492 : ASMJIT_PROPAGATE(removeUnreachableCode());
176 :
177 27492 : ASMJIT_PROPAGATE(buildCFGDominators());
178 27492 : ASMJIT_PROPAGATE(buildLiveness());
179 27492 : ASMJIT_PROPAGATE(assignArgIndexToWorkRegs());
180 :
181 : #ifndef ASMJIT_NO_LOGGING
182 27492 : if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate))
183 0 : ASMJIT_PROPAGATE(annotateCode());
184 : #endif
185 :
186 27492 : ASMJIT_PROPAGATE(runGlobalAllocator());
187 27492 : ASMJIT_PROPAGATE(runLocalAllocator());
188 :
189 27492 : ASMJIT_PROPAGATE(updateStackFrame());
190 27492 : ASMJIT_PROPAGATE(insertPrologEpilog());
191 :
192 27492 : ASMJIT_PROPAGATE(rewrite());
193 :
194 : return kErrorOk;
195 : }
196 :
197 : // BaseRAPass - CFG - Basic Block Management
198 : // =========================================
199 :
200 54984 : RABlock* BaseRAPass::newBlock(BaseNode* initialNode) noexcept {
201 54984 : RABlock* block = zone()->newT<RABlock>(this);
202 54984 : if (ASMJIT_UNLIKELY(!block))
203 : return nullptr;
204 :
205 : block->setFirst(initialNode);
206 : block->setLast(initialNode);
207 :
208 54984 : _createdBlockCount++;
209 54984 : return block;
210 : }
211 :
212 27492 : RABlock* BaseRAPass::newBlockOrExistingAt(LabelNode* cbLabel, BaseNode** stoppedAt) noexcept {
213 27492 : if (cbLabel->hasPassData())
214 : return cbLabel->passData<RABlock>();
215 :
216 : FuncNode* func = this->func();
217 : BaseNode* node = cbLabel->prev();
218 : RABlock* block = nullptr;
219 :
220 : // Try to find some label, but terminate the loop on any code. We try hard to coalesce code that contains two
221 : // consecutive labels or a combination of non-code nodes between 2 or more labels.
222 : //
223 : // Possible cases that would share the same basic block:
224 : //
225 : // 1. Two or more consecutive labels:
226 : // Label1:
227 : // Label2:
228 : //
229 : // 2. Two or more labels separated by non-code nodes:
230 : // Label1:
231 : // ; Some comment...
232 : // .align 16
233 : // Label2:
234 : size_t nPendingLabels = 0;
235 :
236 27492 : while (node) {
237 27492 : if (node->type() == NodeType::kLabel) {
238 : // Function has a different NodeType, just make sure this was not messed up as we must never associate
239 : // BasicBlock with a `func` itself.
240 : ASMJIT_ASSERT(node != func);
241 :
242 : block = node->passData<RABlock>();
243 0 : if (block) {
244 : // Exit node has always a block associated with it. If we went here it means that `cbLabel` passed here
245 : // is after the end of the function and cannot be merged with the function exit block.
246 0 : if (node == func->exitNode())
247 : block = nullptr;
248 : break;
249 : }
250 :
251 0 : nPendingLabels++;
252 : }
253 27492 : else if (node->type() == NodeType::kAlign) {
254 : // Align node is fine.
255 : }
256 : else {
257 : break;
258 : }
259 :
260 : node = node->prev();
261 : }
262 :
263 27492 : if (stoppedAt)
264 27492 : *stoppedAt = node;
265 :
266 27492 : if (!block) {
267 27492 : block = newBlock();
268 27492 : if (ASMJIT_UNLIKELY(!block))
269 : return nullptr;
270 : }
271 :
272 : cbLabel->setPassData<RABlock>(block);
273 : node = cbLabel;
274 :
275 27492 : while (nPendingLabels) {
276 : node = node->prev();
277 : for (;;) {
278 0 : if (node->type() == NodeType::kLabel) {
279 : node->setPassData<RABlock>(block);
280 0 : nPendingLabels--;
281 0 : break;
282 : }
283 :
284 : node = node->prev();
285 : ASMJIT_ASSERT(node != nullptr);
286 : }
287 : }
288 :
289 27492 : if (!block->first()) {
290 : block->setFirst(node);
291 : block->setLast(cbLabel);
292 : }
293 :
294 : return block;
295 : }
296 :
297 54984 : Error BaseRAPass::addBlock(RABlock* block) noexcept {
298 54984 : ASMJIT_PROPAGATE(_blocks.willGrow(allocator()));
299 :
300 54984 : block->_blockId = blockCount();
301 : _blocks.appendUnsafe(block);
302 54984 : return kErrorOk;
303 : }
304 :
305 : // BaseRAPass - CFG - Build
306 : // ========================
307 :
308 27492 : Error BaseRAPass::initSharedAssignments(const ZoneVector<uint32_t>& sharedAssignmentsMap) noexcept {
309 27492 : if (sharedAssignmentsMap.empty())
310 : return kErrorOk;
311 :
312 : uint32_t count = 0;
313 0 : for (RABlock* block : _blocks) {
314 0 : if (block->hasSharedAssignmentId()) {
315 0 : uint32_t sharedAssignmentId = sharedAssignmentsMap[block->sharedAssignmentId()];
316 : block->setSharedAssignmentId(sharedAssignmentId);
317 0 : count = Support::max(count, sharedAssignmentId + 1);
318 : }
319 : }
320 :
321 0 : ASMJIT_PROPAGATE(_sharedAssignments.resize(allocator(), count));
322 :
323 : // Aggregate all entry scratch GP regs from blocks of the same assignment to the assignment itself. It will then be
324 : // used instead of RABlock's own scratch regs mask, as shared assignments have precedence.
325 0 : for (RABlock* block : _blocks) {
326 0 : if (block->hasJumpTable()) {
327 : const RABlocks& successors = block->successors();
328 0 : if (!successors.empty()) {
329 0 : RABlock* firstSuccessor = successors[0];
330 : // NOTE: Shared assignments connect all possible successors so we only need the first to propagate exit scratch
331 : // GP registers.
332 : ASMJIT_ASSERT(firstSuccessor->hasSharedAssignmentId());
333 0 : RASharedAssignment& sa = _sharedAssignments[firstSuccessor->sharedAssignmentId()];
334 : sa.addEntryScratchGpRegs(block->exitScratchGpRegs());
335 : }
336 : }
337 0 : if (block->hasSharedAssignmentId()) {
338 0 : RASharedAssignment& sa = _sharedAssignments[block->sharedAssignmentId()];
339 0 : sa.addEntryScratchGpRegs(block->_entryScratchGpRegs);
340 : }
341 : }
342 :
343 : return kErrorOk;
344 : }
345 :
346 : // BaseRAPass - CFG - Views Order
347 : // ==============================
348 :
349 : class RABlockVisitItem {
350 : public:
351 : inline RABlockVisitItem(RABlock* block, uint32_t index) noexcept
352 27492 : : _block(block),
353 27492 : _index(index) {}
354 :
355 : inline RABlockVisitItem(const RABlockVisitItem& other) noexcept
356 27492 : : _block(other._block),
357 27492 : _index(other._index) {}
358 :
359 : inline RABlockVisitItem& operator=(const RABlockVisitItem& other) noexcept = default;
360 :
361 27492 : inline RABlock* block() const noexcept { return _block; }
362 27492 : inline uint32_t index() const noexcept { return _index; }
363 :
364 : RABlock* _block;
365 : uint32_t _index;
366 : };
367 :
368 27492 : Error BaseRAPass::buildCFGViews() noexcept {
369 : #ifndef ASMJIT_NO_LOGGING
370 : Logger* logger = getLoggerIf(DiagnosticOptions::kRADebugCFG);
371 0 : ASMJIT_RA_LOG_FORMAT("[BuildCFGViews]\n");
372 : #endif
373 :
374 : uint32_t count = blockCount();
375 27492 : if (ASMJIT_UNLIKELY(!count)) return kErrorOk;
376 :
377 27492 : ASMJIT_PROPAGATE(_pov.reserve(allocator(), count));
378 :
379 : ZoneStack<RABlockVisitItem> stack;
380 27492 : ASMJIT_PROPAGATE(stack.init(allocator()));
381 :
382 : ZoneBitVector visited;
383 27492 : ASMJIT_PROPAGATE(visited.resize(allocator(), count));
384 :
385 27492 : RABlock* current = _blocks[0];
386 : uint32_t i = 0;
387 :
388 : for (;;) {
389 : for (;;) {
390 82476 : if (i >= current->successors().size())
391 : break;
392 :
393 : // Skip if already visited.
394 27492 : RABlock* child = current->successors()[i++];
395 27492 : if (visited.bitAt(child->blockId()))
396 0 : continue;
397 :
398 : // Mark as visited to prevent visiting the same block multiple times.
399 : visited.setBit(child->blockId(), true);
400 :
401 : // Add the current block on the stack, we will get back to it later.
402 27492 : ASMJIT_PROPAGATE(stack.append(RABlockVisitItem(current, i)));
403 27492 : current = child;
404 : i = 0;
405 : }
406 :
407 : current->makeReachable();
408 54984 : current->_povOrder = _pov.size();
409 : _pov.appendUnsafe(current);
410 :
411 54984 : if (stack.empty())
412 : break;
413 :
414 27492 : RABlockVisitItem top = stack.pop();
415 27492 : current = top.block();
416 : i = top.index();
417 27492 : }
418 :
419 27492 : ASMJIT_RA_LOG_COMPLEX({
420 : StringTmp<1024> sb;
421 : for (RABlock* block : blocks()) {
422 : sb.clear();
423 : if (block->hasSuccessors()) {
424 : sb.appendFormat(" #%u -> {", block->blockId());
425 : _dumpBlockIds(sb, block->successors());
426 : sb.append("}\n");
427 : }
428 : else {
429 : sb.appendFormat(" #%u -> {Exit}\n", block->blockId());
430 : }
431 : logger->log(sb);
432 : }
433 : });
434 :
435 27492 : visited.release(allocator());
436 27492 : return kErrorOk;
437 : }
438 :
439 : // BaseRAPass - CFG - Dominators
440 : // =============================
441 :
442 : static ASMJIT_FORCE_INLINE RABlock* intersectBlocks(RABlock* b1, RABlock* b2) noexcept {
443 0 : while (b1 != b2) {
444 0 : while (b2->povOrder() > b1->povOrder()) b1 = b1->iDom();
445 0 : while (b1->povOrder() > b2->povOrder()) b2 = b2->iDom();
446 : }
447 : return b1;
448 : }
449 :
450 : // Based on "A Simple, Fast Dominance Algorithm".
451 27492 : Error BaseRAPass::buildCFGDominators() noexcept {
452 : #ifndef ASMJIT_NO_LOGGING
453 : Logger* logger = getLoggerIf(DiagnosticOptions::kRADebugCFG);
454 0 : ASMJIT_RA_LOG_FORMAT("[BuildCFGDominators]\n");
455 : #endif
456 :
457 27492 : if (_blocks.empty())
458 : return kErrorOk;
459 :
460 : RABlock* entryBlock = this->entryBlock();
461 : entryBlock->setIDom(entryBlock);
462 :
463 : bool changed = true;
464 : uint32_t nIters = 0;
465 :
466 82476 : while (changed) {
467 54984 : nIters++;
468 : changed = false;
469 :
470 : uint32_t i = _pov.size();
471 164952 : while (i) {
472 109968 : RABlock* block = _pov[--i];
473 109968 : if (block == entryBlock)
474 54984 : continue;
475 :
476 : RABlock* iDom = nullptr;
477 : const RABlocks& preds = block->predecessors();
478 :
479 : uint32_t j = preds.size();
480 109968 : while (j) {
481 54984 : RABlock* p = preds[--j];
482 54984 : if (!p->iDom())
483 0 : continue;
484 54984 : iDom = !iDom ? p : intersectBlocks(iDom, p);
485 : }
486 :
487 54984 : if (block->iDom() != iDom) {
488 27492 : ASMJIT_ASSUME(iDom != nullptr);
489 27492 : ASMJIT_RA_LOG_FORMAT(" IDom of #%u -> #%u\n", block->blockId(), iDom->blockId());
490 : block->setIDom(iDom);
491 : changed = true;
492 : }
493 : }
494 : }
495 :
496 27492 : ASMJIT_RA_LOG_FORMAT(" Done (%u iterations)\n", nIters);
497 : return kErrorOk;
498 : }
499 :
500 0 : bool BaseRAPass::_strictlyDominates(const RABlock* a, const RABlock* b) const noexcept {
501 : ASMJIT_ASSERT(a != nullptr); // There must be at least one block if this function is
502 : ASMJIT_ASSERT(b != nullptr); // called, as both `a` and `b` must be valid blocks.
503 : ASMJIT_ASSERT(a != b); // Checked by `dominates()` and `strictlyDominates()`.
504 :
505 : // Nothing strictly dominates the entry block.
506 : const RABlock* entryBlock = this->entryBlock();
507 0 : if (a == entryBlock)
508 : return false;
509 :
510 : const RABlock* iDom = b->iDom();
511 0 : while (iDom != a && iDom != entryBlock)
512 : iDom = iDom->iDom();
513 :
514 : return iDom != entryBlock;
515 : }
516 :
517 0 : const RABlock* BaseRAPass::_nearestCommonDominator(const RABlock* a, const RABlock* b) const noexcept {
518 : ASMJIT_ASSERT(a != nullptr); // There must be at least one block if this function is
519 : ASMJIT_ASSERT(b != nullptr); // called, as both `a` and `b` must be valid blocks.
520 : ASMJIT_ASSERT(a != b); // Checked by `dominates()` and `properlyDominates()`.
521 :
522 0 : if (a == b)
523 : return a;
524 :
525 : // If `a` strictly dominates `b` then `a` is the nearest common dominator.
526 0 : if (_strictlyDominates(a, b))
527 : return a;
528 :
529 : // If `b` strictly dominates `a` then `b` is the nearest common dominator.
530 0 : if (_strictlyDominates(b, a))
531 : return b;
532 :
533 : const RABlock* entryBlock = this->entryBlock();
534 : uint64_t timestamp = nextTimestamp();
535 :
536 : // Mark all A's dominators.
537 : const RABlock* block = a->iDom();
538 0 : while (block != entryBlock) {
539 : block->setTimestamp(timestamp);
540 : block = block->iDom();
541 : }
542 :
543 : // Check all B's dominators against marked dominators of A.
544 : block = b->iDom();
545 0 : while (block != entryBlock) {
546 0 : if (block->hasTimestamp(timestamp))
547 : return block;
548 : block = block->iDom();
549 : }
550 :
551 : return entryBlock;
552 : }
553 :
554 : // BaseRAPass - CFG - Utilities
555 : // ============================
556 :
557 27492 : Error BaseRAPass::removeUnreachableCode() noexcept {
558 : uint32_t numAllBlocks = blockCount();
559 : uint32_t numReachableBlocks = reachableBlockCount();
560 :
561 : // All reachable -> nothing to do.
562 27492 : if (numAllBlocks == numReachableBlocks)
563 : return kErrorOk;
564 :
565 : #ifndef ASMJIT_NO_LOGGING
566 : StringTmp<256> sb;
567 : Logger* logger = getLoggerIf(DiagnosticOptions::kRADebugUnreachable);
568 0 : ASMJIT_RA_LOG_FORMAT("[RemoveUnreachableCode - detected %u of %u unreachable blocks]\n", numAllBlocks - numReachableBlocks, numAllBlocks);
569 : #endif
570 :
571 0 : for (uint32_t i = 0; i < numAllBlocks; i++) {
572 0 : RABlock* block = _blocks[i];
573 0 : if (block->isReachable())
574 0 : continue;
575 :
576 0 : ASMJIT_RA_LOG_FORMAT(" Removing code from unreachable block {%u}\n", i);
577 : BaseNode* first = block->first();
578 : BaseNode* last = block->last();
579 :
580 : BaseNode* beforeFirst = first->prev();
581 : BaseNode* afterLast = last->next();
582 :
583 : BaseNode* node = first;
584 0 : while (node != afterLast) {
585 : BaseNode* next = node->next();
586 :
587 0 : if (node->isCode() || node->isRemovable()) {
588 : #ifndef ASMJIT_NO_LOGGING
589 0 : if (logger) {
590 0 : sb.clear();
591 0 : Formatter::formatNode(sb, _formatOptions, cc(), node);
592 0 : logger->logf(" %s\n", sb.data());
593 : }
594 : #endif
595 0 : cc()->removeNode(node);
596 : }
597 : node = next;
598 : }
599 :
600 0 : if (beforeFirst->next() == afterLast) {
601 : block->setFirst(nullptr);
602 : block->setLast(nullptr);
603 : }
604 : else {
605 : block->setFirst(beforeFirst->next());
606 : block->setLast(afterLast->prev());
607 : }
608 : }
609 :
610 : return kErrorOk;
611 : }
612 :
613 0 : BaseNode* BaseRAPass::findSuccessorStartingAt(BaseNode* node) noexcept {
614 0 : while (node && (node->isInformative() || node->hasNoEffect()))
615 : node = node->next();
616 0 : return node;
617 : }
618 :
619 27492 : bool BaseRAPass::isNextTo(BaseNode* node, BaseNode* target) noexcept {
620 : for (;;) {
621 : node = node->next();
622 27492 : if (node == target)
623 : return true;
624 :
625 0 : if (!node)
626 : return false;
627 :
628 0 : if (node->isCode() || node->isData())
629 : return false;
630 : }
631 : }
632 :
633 : // BaseRAPass - Registers - VirtReg / WorkReg Mapping
634 : // ==================================================
635 :
636 271314 : Error BaseRAPass::_asWorkReg(VirtReg* vReg, RAWorkReg** out) noexcept {
637 : // Checked by `asWorkReg()` - must be true.
638 : ASMJIT_ASSERT(vReg->_workReg == nullptr);
639 :
640 271314 : RegGroup group = vReg->group();
641 : ASMJIT_ASSERT(group <= RegGroup::kMaxVirt);
642 :
643 : RAWorkRegs& wRegs = workRegs();
644 : RAWorkRegs& wRegsByGroup = workRegs(group);
645 :
646 271314 : ASMJIT_PROPAGATE(wRegs.willGrow(allocator()));
647 271314 : ASMJIT_PROPAGATE(wRegsByGroup.willGrow(allocator()));
648 :
649 271314 : RAWorkReg* wReg = zone()->newT<RAWorkReg>(vReg, wRegs.size());
650 271314 : if (ASMJIT_UNLIKELY(!wReg))
651 : return DebugUtils::errored(kErrorOutOfMemory);
652 :
653 : vReg->setWorkReg(wReg);
654 271314 : if (!vReg->isStack())
655 : wReg->setRegByteMask(Support::lsbMask<uint64_t>(vReg->virtSize()));
656 : wRegs.appendUnsafe(wReg);
657 : wRegsByGroup.appendUnsafe(wReg);
658 :
659 : // Only used by RA logging.
660 271314 : _maxWorkRegNameSize = Support::max(_maxWorkRegNameSize, vReg->nameSize());
661 :
662 271314 : *out = wReg;
663 271314 : return kErrorOk;
664 : }
665 :
666 82476 : RAAssignment::WorkToPhysMap* BaseRAPass::newWorkToPhysMap() noexcept {
667 : uint32_t count = workRegCount();
668 82476 : size_t size = WorkToPhysMap::sizeOf(count);
669 :
670 : // If no registers are used it could be zero, in that case return a dummy
671 : // map instead of NULL.
672 82476 : if (ASMJIT_UNLIKELY(!size)) {
673 : static const RAAssignment::WorkToPhysMap nullMap = {{ 0 }};
674 : return const_cast<RAAssignment::WorkToPhysMap*>(&nullMap);
675 : }
676 :
677 : WorkToPhysMap* map = zone()->allocT<WorkToPhysMap>(size);
678 82476 : if (ASMJIT_UNLIKELY(!map))
679 : return nullptr;
680 :
681 : map->reset(count);
682 : return map;
683 : }
684 :
685 54984 : RAAssignment::PhysToWorkMap* BaseRAPass::newPhysToWorkMap() noexcept {
686 : uint32_t count = physRegTotal();
687 54984 : size_t size = PhysToWorkMap::sizeOf(count);
688 :
689 : PhysToWorkMap* map = zone()->allocT<PhysToWorkMap>(size);
690 54984 : if (ASMJIT_UNLIKELY(!map))
691 : return nullptr;
692 :
693 54984 : map->reset(count);
694 54984 : return map;
695 : }
696 :
697 : // BaseRAPass - Registers - Liveness Analysis and Statistics
698 : // =========================================================
699 :
700 : namespace LiveOps {
701 : typedef ZoneBitVector::BitWord BitWord;
702 :
703 : struct In {
704 : static ASMJIT_FORCE_INLINE BitWord op(BitWord dst, BitWord out, BitWord gen, BitWord kill) noexcept {
705 : DebugUtils::unused(dst);
706 56570 : return (out | gen) & ~kill;
707 : }
708 : };
709 :
710 : template<typename Operator>
711 : static ASMJIT_FORCE_INLINE bool op(BitWord* dst, const BitWord* a, uint32_t n) noexcept {
712 : BitWord changed = 0;
713 :
714 111554 : for (uint32_t i = 0; i < n; i++) {
715 56570 : BitWord before = dst[i];
716 56570 : BitWord after = Operator::op(before, a[i]);
717 :
718 28285 : dst[i] = after;
719 28285 : changed |= (before ^ after);
720 : }
721 :
722 27492 : return changed != 0;
723 : }
724 :
725 : template<typename Operator>
726 : static ASMJIT_FORCE_INLINE bool op(BitWord* dst, const BitWord* a, const BitWord* b, uint32_t n) noexcept {
727 : BitWord changed = 0;
728 :
729 : for (uint32_t i = 0; i < n; i++) {
730 : BitWord before = dst[i];
731 : BitWord after = Operator::op(before, a[i], b[i]);
732 :
733 : dst[i] = after;
734 : changed |= (before ^ after);
735 : }
736 :
737 : return changed != 0;
738 : }
739 :
740 : template<typename Operator>
741 : static ASMJIT_FORCE_INLINE bool op(BitWord* dst, const BitWord* a, const BitWord* b, const BitWord* c, uint32_t n) noexcept {
742 : BitWord changed = 0;
743 :
744 111554 : for (uint32_t i = 0; i < n; i++) {
745 56570 : BitWord before = dst[i];
746 56570 : BitWord after = Operator::op(before, a[i], b[i], c[i]);
747 :
748 56570 : dst[i] = after;
749 0 : changed |= (before ^ after);
750 : }
751 :
752 : return changed != 0;
753 : }
754 :
755 : static ASMJIT_FORCE_INLINE bool recalcInOut(RABlock* block, uint32_t numBitWords, bool initial = false) noexcept {
756 : bool changed = initial;
757 :
758 : const RABlocks& successors = block->successors();
759 : uint32_t numSuccessors = successors.size();
760 :
761 : // Calculate `OUT` based on `IN` of all successors.
762 164952 : for (uint32_t i = 0; i < numSuccessors; i++)
763 82476 : changed |= op<Support::Or>(block->liveOut().data(), successors[i]->liveIn().data(), numBitWords);
764 :
765 : // Calculate `IN` based on `OUT`, `GEN`, and `KILL` bits.
766 54984 : if (changed)
767 : changed = op<In>(block->liveIn().data(), block->liveOut().data(), block->gen().data(), block->kill().data(), numBitWords);
768 :
769 : return changed;
770 : }
771 : }
772 :
773 27492 : ASMJIT_FAVOR_SPEED Error BaseRAPass::buildLiveness() noexcept {
774 : #ifndef ASMJIT_NO_LOGGING
775 : Logger* logger = getLoggerIf(DiagnosticOptions::kRADebugLiveness);
776 : StringTmp<512> sb;
777 : #endif
778 :
779 27492 : ASMJIT_RA_LOG_FORMAT("[BuildLiveness]\n");
780 :
781 : uint32_t i;
782 :
783 : uint32_t numAllBlocks = blockCount();
784 : uint32_t numReachableBlocks = reachableBlockCount();
785 :
786 : uint32_t numVisits = numReachableBlocks;
787 : uint32_t numWorkRegs = workRegCount();
788 : uint32_t numBitWords = ZoneBitVector::_wordsPerBits(numWorkRegs);
789 :
790 27492 : if (!numWorkRegs) {
791 0 : ASMJIT_RA_LOG_FORMAT(" Done (no virtual registers)\n");
792 0 : return kErrorOk;
793 : }
794 :
795 : ZoneVector<uint32_t> nUsesPerWorkReg; // Number of USEs of each RAWorkReg.
796 : ZoneVector<uint32_t> nOutsPerWorkReg; // Number of OUTs of each RAWorkReg.
797 : ZoneVector<uint32_t> nInstsPerBlock; // Number of instructions of each RABlock.
798 :
799 27492 : ASMJIT_PROPAGATE(nUsesPerWorkReg.resize(allocator(), numWorkRegs));
800 27492 : ASMJIT_PROPAGATE(nOutsPerWorkReg.resize(allocator(), numWorkRegs));
801 27492 : ASMJIT_PROPAGATE(nInstsPerBlock.resize(allocator(), numAllBlocks));
802 :
803 : // Calculate GEN/KILL of Each Block
804 : // --------------------------------
805 :
806 82476 : for (i = 0; i < numReachableBlocks; i++) {
807 54984 : RABlock* block = _pov[i];
808 54984 : ASMJIT_PROPAGATE(block->resizeLiveBits(numWorkRegs));
809 :
810 : BaseNode* node = block->last();
811 : BaseNode* stop = block->first();
812 :
813 : uint32_t nInsts = 0;
814 : for (;;) {
815 386792 : if (node->isInst()) {
816 : InstNode* inst = node->as<InstNode>();
817 : RAInst* raInst = inst->passData<RAInst>();
818 : ASMJIT_ASSERT(raInst != nullptr);
819 :
820 : RATiedReg* tiedRegs = raInst->tiedRegs();
821 : uint32_t count = raInst->tiedCount();
822 :
823 946262 : for (uint32_t j = 0; j < count; j++) {
824 614454 : RATiedReg* tiedReg = &tiedRegs[j];
825 : uint32_t workId = tiedReg->workId();
826 :
827 : // Update `nUses` and `nOuts`.
828 614454 : nUsesPerWorkReg[workId] += 1u;
829 614454 : nOutsPerWorkReg[workId] += uint32_t(tiedReg->isWrite());
830 :
831 : // Mark as:
832 : // KILL - if this VirtReg is killed afterwards.
833 : // LAST - if this VirtReg is last in this basic block.
834 614454 : if (block->kill().bitAt(workId))
835 : tiedReg->addFlags(RATiedFlags::kKill);
836 602594 : else if (!block->gen().bitAt(workId))
837 : tiedReg->addFlags(RATiedFlags::kLast);
838 :
839 614454 : if (tiedReg->isWriteOnly()) {
840 : // KILL.
841 : block->kill().setBit(workId, true);
842 : }
843 : else {
844 : // GEN.
845 : block->kill().setBit(workId, false);
846 : block->gen().setBit(workId, true);
847 : }
848 :
849 614454 : if (tiedReg->isLeadConsecutive()) {
850 : RAWorkReg* workReg = workRegById(workId);
851 : workReg->markLeadConsecutive();
852 : }
853 :
854 614454 : if (tiedReg->hasConsecutiveParent()) {
855 : RAWorkReg* consecutiveParentReg = workRegById(tiedReg->consecutiveParent());
856 0 : consecutiveParentReg->addImmediateConsecutive(allocator(), workId);
857 : }
858 : }
859 :
860 331808 : nInsts++;
861 : }
862 :
863 386792 : if (node == stop)
864 : break;
865 :
866 : node = node->prev();
867 : ASMJIT_ASSERT(node != nullptr);
868 331808 : }
869 :
870 54984 : nInstsPerBlock[block->blockId()] = nInsts;
871 : }
872 :
873 : // Calculate IN/OUT of Each Block
874 : // ------------------------------
875 :
876 : {
877 : ZoneStack<RABlock*> workList;
878 : ZoneBitVector workBits;
879 :
880 27492 : ASMJIT_PROPAGATE(workList.init(allocator()));
881 27492 : ASMJIT_PROPAGATE(workBits.resize(allocator(), blockCount(), true));
882 :
883 82476 : for (i = 0; i < numReachableBlocks; i++) {
884 54984 : RABlock* block = _pov[i];
885 : LiveOps::recalcInOut(block, numBitWords, true);
886 54984 : ASMJIT_PROPAGATE(workList.append(block));
887 : }
888 :
889 82476 : while (!workList.empty()) {
890 54984 : RABlock* block = workList.popFirst();
891 : uint32_t blockId = block->blockId();
892 :
893 : workBits.setBit(blockId, false);
894 0 : if (LiveOps::recalcInOut(block, numBitWords)) {
895 : const RABlocks& predecessors = block->predecessors();
896 : uint32_t numPredecessors = predecessors.size();
897 :
898 0 : for (uint32_t j = 0; j < numPredecessors; j++) {
899 0 : RABlock* pred = predecessors[j];
900 0 : if (!workBits.bitAt(pred->blockId())) {
901 : workBits.setBit(pred->blockId(), true);
902 0 : ASMJIT_PROPAGATE(workList.append(pred));
903 : }
904 : }
905 : }
906 54984 : numVisits++;
907 : }
908 :
909 : workList.reset();
910 : workBits.release(allocator());
911 : }
912 :
913 27492 : ASMJIT_RA_LOG_COMPLEX({
914 : logger->logf(" LiveIn/Out Done (%u visits)\n", numVisits);
915 : for (i = 0; i < numAllBlocks; i++) {
916 : RABlock* block = _blocks[i];
917 :
918 : ASMJIT_PROPAGATE(sb.assignFormat(" {#%u}\n", block->blockId()));
919 : ASMJIT_PROPAGATE(_dumpBlockLiveness(sb, block));
920 :
921 : logger->log(sb);
922 : }
923 : });
924 :
925 : // Reserve the space in each `RAWorkReg` for references
926 : // ----------------------------------------------------
927 :
928 298806 : for (i = 0; i < numWorkRegs; i++) {
929 : RAWorkReg* workReg = workRegById(i);
930 542628 : ASMJIT_PROPAGATE(workReg->_refs.reserve(allocator(), nUsesPerWorkReg[i]));
931 542628 : ASMJIT_PROPAGATE(workReg->_writes.reserve(allocator(), nOutsPerWorkReg[i]));
932 : }
933 :
934 : // Assign block and instruction positions, build LiveCount and LiveSpans
935 : // ---------------------------------------------------------------------
936 :
937 : uint32_t position = 2;
938 82476 : for (i = 0; i < numAllBlocks; i++) {
939 54984 : RABlock* block = _blocks[i];
940 54984 : if (!block->isReachable())
941 0 : continue;
942 :
943 54984 : BaseNode* node = block->first();
944 : BaseNode* stop = block->last();
945 :
946 54984 : uint32_t endPosition = position + nInstsPerBlock[i] * 2;
947 : block->setFirstPosition(position);
948 : block->setEndPosition(endPosition);
949 :
950 54984 : RALiveCount curLiveCount;
951 54984 : RALiveCount maxLiveCount;
952 :
953 : // Process LIVE-IN.
954 : ZoneBitVector::ForEachBitSet it(block->liveIn());
955 54984 : while (it.hasNext()) {
956 0 : RAWorkReg* workReg = _workRegs[uint32_t(it.next())];
957 0 : curLiveCount[workReg->group()]++;
958 0 : ASMJIT_PROPAGATE(workReg->liveSpans().openAt(allocator(), position, endPosition));
959 : }
960 :
961 : for (;;) {
962 386792 : if (node->isInst()) {
963 : InstNode* inst = node->as<InstNode>();
964 : RAInst* raInst = inst->passData<RAInst>();
965 : ASMJIT_ASSERT(raInst != nullptr);
966 :
967 : RATiedReg* tiedRegs = raInst->tiedRegs();
968 : uint32_t count = raInst->tiedCount();
969 :
970 : inst->setPosition(position);
971 331808 : raInst->_liveCount = curLiveCount;
972 :
973 946262 : for (uint32_t j = 0; j < count; j++) {
974 614454 : RATiedReg* tiedReg = &tiedRegs[j];
975 : uint32_t workId = tiedReg->workId();
976 :
977 : // Create refs and writes.
978 : RAWorkReg* workReg = workRegById(workId);
979 : workReg->_refs.appendUnsafe(node);
980 614454 : if (tiedReg->isWrite())
981 : workReg->_writes.appendUnsafe(node);
982 :
983 : // We couldn't calculate this in previous steps, but since we know all LIVE-OUT at this point it becomes
984 : // trivial. If this is the last instruction that uses this `workReg` and it's not LIVE-OUT then it is
985 : // KILLed here.
986 614454 : if (tiedReg->isLast() && !block->liveOut().bitAt(workId))
987 : tiedReg->addFlags(RATiedFlags::kKill);
988 :
989 : LiveRegSpans& liveSpans = workReg->liveSpans();
990 : bool wasOpen;
991 1228908 : ASMJIT_PROPAGATE(liveSpans.openAt(allocator(), position + !tiedReg->isRead(), endPosition, wasOpen));
992 :
993 : RegGroup group = workReg->group();
994 614454 : if (!wasOpen) {
995 283174 : curLiveCount[group]++;
996 283174 : raInst->_liveCount[group]++;
997 : }
998 :
999 614454 : if (tiedReg->isKill()) {
1000 283174 : liveSpans.closeAt(position + !tiedReg->isRead() + 1);
1001 283174 : curLiveCount[group]--;
1002 : }
1003 :
1004 : // Update `RAWorkReg::useIdMask` and `RAWorkReg::hintRegId`.
1005 614454 : if (tiedReg->hasUseId()) {
1006 : uint32_t useId = tiedReg->useId();
1007 : workReg->addUseIdMask(Support::bitMask(useId));
1008 37365 : if (!workReg->hasHintRegId() && !Support::bitTest(raInst->_clobberedRegs[group], useId))
1009 : workReg->setHintRegId(useId);
1010 : }
1011 :
1012 614454 : if (tiedReg->useRegMask()) {
1013 : workReg->restrictPreferredMask(tiedReg->useRegMask());
1014 604581 : if (workReg->isLeadConsecutive())
1015 : workReg->restrictConsecutiveMask(tiedReg->useRegMask());
1016 : }
1017 :
1018 614454 : if (tiedReg->outRegMask()) {
1019 : workReg->restrictPreferredMask(tiedReg->outRegMask());
1020 614454 : if (workReg->isLeadConsecutive())
1021 : workReg->restrictConsecutiveMask(tiedReg->outRegMask());
1022 : }
1023 :
1024 : // Update `RAWorkReg::clobberedSurvivalMask`.
1025 614454 : if (raInst->_clobberedRegs[group] && !tiedReg->isOutOrKill()) {
1026 : workReg->addClobberSurvivalMask(raInst->_clobberedRegs[group]);
1027 : }
1028 : }
1029 :
1030 331808 : position += 2;
1031 : maxLiveCount.op<Support::Max>(raInst->_liveCount);
1032 : }
1033 :
1034 386792 : if (node == stop)
1035 : break;
1036 :
1037 331808 : node = node->next();
1038 : ASMJIT_ASSERT(node != nullptr);
1039 331808 : }
1040 :
1041 54984 : block->_maxLiveCount = maxLiveCount;
1042 : _globalMaxLiveCount.op<Support::Max>(maxLiveCount);
1043 : ASMJIT_ASSERT(position == block->endPosition());
1044 : }
1045 :
1046 : // Calculate WorkReg statistics
1047 : // ----------------------------
1048 :
1049 298806 : for (i = 0; i < numWorkRegs; i++) {
1050 271314 : RAWorkReg* workReg = _workRegs[i];
1051 :
1052 : LiveRegSpans& spans = workReg->liveSpans();
1053 : uint32_t width = spans.width();
1054 271314 : float freq = width ? float(double(workReg->_refs.size()) / double(width)) : float(0);
1055 :
1056 : RALiveStats& stats = workReg->liveStats();
1057 271314 : stats._width = width;
1058 271314 : stats._freq = freq;
1059 271314 : stats._priority = freq + float(int(workReg->virtReg()->weight())) * 0.01f;
1060 : }
1061 :
1062 27492 : ASMJIT_RA_LOG_COMPLEX({
1063 : sb.clear();
1064 : _dumpLiveSpans(sb);
1065 : logger->log(sb);
1066 : });
1067 :
1068 : nUsesPerWorkReg.release(allocator());
1069 : nOutsPerWorkReg.release(allocator());
1070 : nInstsPerBlock.release(allocator());
1071 :
1072 27492 : return kErrorOk;
1073 : }
1074 :
1075 27492 : Error BaseRAPass::assignArgIndexToWorkRegs() noexcept {
1076 : ZoneBitVector& liveIn = entryBlock()->liveIn();
1077 : uint32_t argCount = func()->argCount();
1078 :
1079 27492 : for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
1080 0 : for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
1081 : // Unassigned argument.
1082 0 : const RegOnly& regArg = func()->argPack(argIndex)[valueIndex];
1083 0 : if (!regArg.isReg() || !cc()->isVirtIdValid(regArg.id()))
1084 0 : continue;
1085 :
1086 : VirtReg* virtReg = cc()->virtRegById(regArg.id());
1087 0 : if (!virtReg)
1088 0 : continue;
1089 :
1090 : // Unreferenced argument.
1091 : RAWorkReg* workReg = virtReg->workReg();
1092 0 : if (!workReg)
1093 0 : continue;
1094 :
1095 : // Overwritten argument.
1096 : uint32_t workId = workReg->workId();
1097 0 : if (!liveIn.bitAt(workId))
1098 0 : continue;
1099 :
1100 : workReg->setArgIndex(argIndex, valueIndex);
1101 : const FuncValue& arg = func()->detail().arg(argIndex, valueIndex);
1102 :
1103 0 : if (arg.isReg() && _archTraits->regTypeToGroup(arg.regType()) == workReg->group()) {
1104 : workReg->setHintRegId(arg.regId());
1105 : }
1106 : }
1107 : }
1108 :
1109 27492 : return kErrorOk;
1110 : }
1111 :
1112 : // BaseRAPass - Allocation - Global
1113 : // ================================
1114 :
1115 : #ifndef ASMJIT_NO_LOGGING
1116 0 : static void RAPass_dumpSpans(String& sb, uint32_t index, const LiveRegSpans& liveSpans) noexcept {
1117 : sb.appendFormat(" %02u: ", index);
1118 :
1119 0 : for (uint32_t i = 0; i < liveSpans.size(); i++) {
1120 : const LiveRegSpan& liveSpan = liveSpans[i];
1121 0 : if (i) sb.append(", ");
1122 0 : sb.appendFormat("[%u:%u@%u]", liveSpan.a, liveSpan.b, liveSpan.id);
1123 : }
1124 :
1125 : sb.append('\n');
1126 0 : }
1127 : #endif
1128 :
1129 27492 : Error BaseRAPass::runGlobalAllocator() noexcept {
1130 27492 : ASMJIT_PROPAGATE(initGlobalLiveSpans());
1131 :
1132 137460 : for (RegGroup group : RegGroupVirtValues{}) {
1133 109968 : ASMJIT_PROPAGATE(binPack(group));
1134 : }
1135 :
1136 : return kErrorOk;
1137 : }
1138 :
1139 27492 : ASMJIT_FAVOR_SPEED Error BaseRAPass::initGlobalLiveSpans() noexcept {
1140 137460 : for (RegGroup group : RegGroupVirtValues{}) {
1141 109968 : size_t physCount = _physRegCount[group];
1142 : LiveRegSpans* liveSpans = nullptr;
1143 :
1144 109968 : if (physCount) {
1145 109968 : liveSpans = allocator()->allocT<LiveRegSpans>(physCount * sizeof(LiveRegSpans));
1146 109968 : if (ASMJIT_UNLIKELY(!liveSpans))
1147 : return DebugUtils::errored(kErrorOutOfMemory);
1148 :
1149 1429584 : for (size_t physId = 0; physId < physCount; physId++)
1150 1319616 : new(&liveSpans[physId]) LiveRegSpans();
1151 : }
1152 :
1153 109968 : _globalLiveSpans[group] = liveSpans;
1154 : }
1155 :
1156 : return kErrorOk;
1157 : }
1158 :
1159 : struct RAConsecutiveReg {
1160 : RAWorkReg* workReg;
1161 : RAWorkReg* parentReg;
1162 : };
1163 :
1164 109968 : ASMJIT_FAVOR_SPEED Error BaseRAPass::binPack(RegGroup group) noexcept {
1165 109968 : if (workRegCount(group) == 0)
1166 : return kErrorOk;
1167 :
1168 : #ifndef ASMJIT_NO_LOGGING
1169 : Logger* logger = getLoggerIf(DiagnosticOptions::kRADebugAssignment);
1170 : StringTmp<512> sb;
1171 :
1172 54984 : ASMJIT_RA_LOG_FORMAT("[BinPack] Available=%u (0x%08X) Count=%u RegGroup=%u\n",
1173 : Support::popcnt(_availableRegs[group]),
1174 : _availableRegs[group],
1175 : workRegCount(group),
1176 : uint32_t(group));
1177 : #endif
1178 :
1179 : uint32_t i;
1180 54984 : uint32_t physCount = _physRegCount[group];
1181 :
1182 : RAWorkRegs workRegs;
1183 : ZoneVector<RAConsecutiveReg> consecutiveRegs;
1184 : LiveRegSpans tmpSpans;
1185 :
1186 54984 : ASMJIT_PROPAGATE(workRegs.concat(allocator(), this->workRegs(group)));
1187 54984 : workRegs.sort([](const RAWorkReg* a, const RAWorkReg* b) noexcept {
1188 669150 : return b->liveStats().priority() - a->liveStats().priority();
1189 : });
1190 :
1191 : uint32_t numWorkRegs = workRegs.size();
1192 54984 : RegMask availableRegs = _availableRegs[group];
1193 :
1194 : // First try to pack everything that provides register-id hint as these are most likely function arguments and fixed
1195 : // (precolored) virtual registers.
1196 54984 : if (!workRegs.empty()) {
1197 : uint32_t dstIndex = 0;
1198 :
1199 326298 : for (i = 0; i < numWorkRegs; i++) {
1200 271314 : RAWorkReg* workReg = workRegs[i];
1201 :
1202 271314 : if (workReg->isLeadConsecutive()) {
1203 0 : ASMJIT_PROPAGATE(consecutiveRegs.append(allocator(), RAConsecutiveReg{workReg, nullptr}));
1204 : workReg->markProcessedConsecutive();
1205 : }
1206 :
1207 271314 : if (workReg->hasHintRegId()) {
1208 : uint32_t physId = workReg->hintRegId();
1209 27492 : if (Support::bitTest(availableRegs, physId)) {
1210 27492 : LiveRegSpans& live = _globalLiveSpans[group][physId];
1211 : Error err = tmpSpans.nonOverlappingUnionOf(allocator(), live, workReg->liveSpans(), LiveRegData(workReg->virtId()));
1212 :
1213 27492 : if (err == kErrorOk) {
1214 : live.swap(tmpSpans);
1215 : workReg->setHomeRegId(physId);
1216 : workReg->markAllocated();
1217 27492 : continue;
1218 : }
1219 :
1220 0 : if (err != 0xFFFFFFFFu)
1221 0 : return err;
1222 : }
1223 : }
1224 :
1225 243822 : workRegs[dstIndex++] = workReg;
1226 : }
1227 :
1228 : workRegs._setSize(dstIndex);
1229 : numWorkRegs = dstIndex;
1230 : }
1231 :
1232 : // Allocate consecutive registers - both leads and all consecutives. This is important and prioritized over the rest,
1233 : // because once a lead is allocated we really need to allocate its consecutives, otherwise we may bin pack other
1234 : // registers into their places, which would result in wrong hints to the local allocator, and then into many moves
1235 : // or spills.
1236 54984 : if (!consecutiveRegs.empty()) {
1237 : // This loop appends all other consecutive registers into `consecutiveRegs` array. Leads are at the beginning,
1238 : // non-leads follow.
1239 : i = 0;
1240 : for (;;) {
1241 : uint32_t stop = consecutiveRegs.size();
1242 0 : if (i == stop)
1243 : break;
1244 :
1245 0 : while (i < stop) {
1246 0 : RAWorkReg* workReg = consecutiveRegs[i].workReg;
1247 0 : if (workReg->hasImmediateConsecutives()) {
1248 : ZoneBitVector::ForEachBitSet it(workReg->immediateConsecutives());
1249 0 : while (it.hasNext()) {
1250 : uint32_t consecutiveWorkId = uint32_t(it.next());
1251 : RAWorkReg* consecutiveReg = workRegById(consecutiveWorkId);
1252 0 : if (!consecutiveReg->isProcessedConsecutive()) {
1253 0 : ASMJIT_PROPAGATE(consecutiveRegs.append(allocator(), RAConsecutiveReg{consecutiveReg, workReg}));
1254 : consecutiveReg->markProcessedConsecutive();
1255 : }
1256 : }
1257 : }
1258 0 : i++;
1259 : }
1260 : }
1261 :
1262 : uint32_t numConsecutiveRegs = consecutiveRegs.size();
1263 0 : for (i = 0; i < numConsecutiveRegs; i++) {
1264 0 : RAWorkReg* workReg = consecutiveRegs[i].workReg;
1265 0 : if (workReg->isAllocated())
1266 0 : continue;
1267 :
1268 0 : RAWorkReg* parentReg = consecutiveRegs[i].parentReg;
1269 : RegMask physRegs = 0;
1270 :
1271 0 : if (!parentReg) {
1272 0 : physRegs = availableRegs & workReg->preferredMask();
1273 0 : if (!physRegs) {
1274 0 : physRegs = availableRegs & workReg->consecutiveMask();
1275 :
1276 : // NOTE: This should never be true as it would mean we would never allocate this virtual register
1277 : // (not here, and not later when local register allocator processes RATiedReg sets).
1278 0 : if (ASMJIT_UNLIKELY(!physRegs))
1279 : return DebugUtils::errored(kErrorConsecutiveRegsAllocation);
1280 : }
1281 : }
1282 0 : else if (parentReg->hasHomeRegId()) {
1283 0 : uint32_t consecutiveId = parentReg->homeRegId() + 1;
1284 :
1285 : // NOTE: We don't support wrapping. If this goes beyond all allocable registers there is something wrong.
1286 0 : if (consecutiveId > 31 || !Support::bitTest(availableRegs, consecutiveId))
1287 : return DebugUtils::errored(kErrorConsecutiveRegsAllocation);
1288 :
1289 : workReg->setHintRegId(consecutiveId);
1290 : physRegs = Support::bitMask(consecutiveId);
1291 : }
1292 :
1293 0 : while (physRegs) {
1294 0 : uint32_t physId = Support::bitSizeOf<RegMask>() - 1 - Support::clz(physRegs);
1295 :
1296 0 : LiveRegSpans& live = _globalLiveSpans[group][physId];
1297 : Error err = tmpSpans.nonOverlappingUnionOf(allocator(), live, workReg->liveSpans(), LiveRegData(workReg->virtId()));
1298 :
1299 : if (err == kErrorOk) {
1300 : workReg->setHomeRegId(physId);
1301 : workReg->markAllocated();
1302 : live.swap(tmpSpans);
1303 : break;
1304 : }
1305 :
1306 0 : if (ASMJIT_UNLIKELY(err != 0xFFFFFFFFu))
1307 : return err;
1308 :
1309 0 : physRegs ^= Support::bitMask(physId);
1310 : }
1311 : }
1312 : }
1313 :
1314 : // Try to pack the rest.
1315 54984 : if (!workRegs.empty()) {
1316 : uint32_t dstIndex = 0;
1317 :
1318 295549 : for (i = 0; i < numWorkRegs; i++) {
1319 243822 : RAWorkReg* workReg = workRegs[i];
1320 :
1321 243822 : if (workReg->isAllocated())
1322 0 : continue;
1323 :
1324 : RegMask physRegs = availableRegs;
1325 243822 : if (physRegs & workReg->preferredMask())
1326 : physRegs &= workReg->preferredMask();
1327 :
1328 555246 : while (physRegs) {
1329 : RegMask preferredMask = physRegs;
1330 : uint32_t physId = Support::ctz(preferredMask);
1331 :
1332 544801 : if (workReg->clobberSurvivalMask()) {
1333 1002 : preferredMask &= workReg->clobberSurvivalMask();
1334 1002 : if (preferredMask)
1335 : physId = Support::ctz(preferredMask);
1336 : }
1337 :
1338 544801 : LiveRegSpans& live = _globalLiveSpans[group][physId];
1339 : Error err = tmpSpans.nonOverlappingUnionOf(allocator(), live, workReg->liveSpans(), LiveRegData(workReg->virtId()));
1340 :
1341 : if (err == kErrorOk) {
1342 : workReg->setHomeRegId(physId);
1343 : workReg->markAllocated();
1344 : live.swap(tmpSpans);
1345 : break;
1346 : }
1347 :
1348 311424 : if (ASMJIT_UNLIKELY(err != 0xFFFFFFFFu))
1349 : return err;
1350 :
1351 311424 : physRegs ^= Support::bitMask(physId);
1352 : }
1353 :
1354 : // Keep it in `workRegs` if it was not allocated.
1355 243822 : if (!physRegs)
1356 10445 : workRegs[dstIndex++] = workReg;
1357 : }
1358 :
1359 : workRegs._setSize(dstIndex);
1360 : numWorkRegs = dstIndex;
1361 : }
1362 :
1363 54984 : ASMJIT_RA_LOG_COMPLEX({
1364 : for (uint32_t physId = 0; physId < physCount; physId++) {
1365 : LiveRegSpans& live = _globalLiveSpans[group][physId];
1366 : if (live.empty())
1367 : continue;
1368 :
1369 : sb.clear();
1370 : RAPass_dumpSpans(sb, physId, live);
1371 : logger->log(sb);
1372 : }
1373 : });
1374 :
1375 : // Maybe unused if logging is disabled.
1376 : DebugUtils::unused(physCount);
1377 :
1378 54984 : if (workRegs.empty()) {
1379 53029 : ASMJIT_RA_LOG_FORMAT(" Completed.\n");
1380 : }
1381 : else {
1382 : _strategy[group].setType(RAStrategyType::kComplex);
1383 12400 : for (RAWorkReg* workReg : workRegs)
1384 : workReg->markStackPreferred();
1385 :
1386 1955 : ASMJIT_RA_LOG_COMPLEX({
1387 : uint32_t count = workRegs.size();
1388 : sb.clear();
1389 : sb.appendFormat(" Unassigned (%u): ", count);
1390 : for (i = 0; i < numWorkRegs; i++) {
1391 : RAWorkReg* workReg = workRegs[i];
1392 : if (i) sb.append(", ");
1393 : sb.append(workReg->name());
1394 : }
1395 : sb.append('\n');
1396 : logger->log(sb);
1397 : });
1398 : }
1399 :
1400 : return kErrorOk;
1401 : }
1402 :
1403 : // BaseRAPass - Allocation - Local
1404 : // ===============================
1405 :
1406 27492 : Error BaseRAPass::runLocalAllocator() noexcept {
1407 27492 : RALocalAllocator lra(this);
1408 27492 : ASMJIT_PROPAGATE(lra.init());
1409 :
1410 27492 : if (!blockCount())
1411 : return kErrorOk;
1412 :
1413 : // The allocation is done when this reaches zero.
1414 : uint32_t blocksRemaining = reachableBlockCount();
1415 :
1416 : // Current block.
1417 : uint32_t blockId = 0;
1418 27492 : RABlock* block = _blocks[blockId];
1419 :
1420 : // The first block (entry) must always be reachable.
1421 : ASMJIT_ASSERT(block->isReachable());
1422 :
1423 : // Assign function arguments for the initial block. The `lra` is valid now.
1424 27492 : lra.makeInitialAssignment();
1425 27492 : ASMJIT_PROPAGATE(setBlockEntryAssignment(block, block, lra._curAssignment));
1426 :
1427 : // The loop starts from the first block and iterates blocks in order, however, the algorithm also allows to jump to
1428 : // any other block when finished if it's a jump target. In-order iteration just makes sure that all blocks are visited.
1429 : for (;;) {
1430 : BaseNode* first = block->first();
1431 : BaseNode* last = block->last();
1432 54984 : BaseNode* terminator = block->hasTerminator() ? last : nullptr;
1433 :
1434 : BaseNode* beforeFirst = first->prev();
1435 : BaseNode* afterLast = last->next();
1436 :
1437 : bool unconditionalJump = false;
1438 : RABlock* consecutive = nullptr;
1439 :
1440 54984 : if (block->hasSuccessors())
1441 27492 : consecutive = block->successors()[0];
1442 :
1443 : lra.setBlock(block);
1444 : block->makeAllocated();
1445 :
1446 : BaseNode* node = first;
1447 441776 : while (node != afterLast) {
1448 : BaseNode* next = node->next();
1449 386792 : if (node->isInst()) {
1450 : InstNode* inst = node->as<InstNode>();
1451 :
1452 331808 : if (ASMJIT_UNLIKELY(inst == terminator)) {
1453 : const RABlocks& successors = block->successors();
1454 0 : if (block->hasConsecutive()) {
1455 0 : ASMJIT_PROPAGATE(lra.allocBranch(inst, successors.last(), successors.first()));
1456 :
1457 : node = next;
1458 0 : continue;
1459 0 : }
1460 0 : else if (successors.size() > 1) {
1461 0 : RABlock* cont = block->hasConsecutive() ? successors.first() : nullptr;
1462 0 : ASMJIT_PROPAGATE(lra.allocJumpTable(inst, successors, cont));
1463 :
1464 : node = next;
1465 0 : continue;
1466 0 : }
1467 : else {
1468 : // Otherwise this is an unconditional jump, special handling isn't required.
1469 : unconditionalJump = true;
1470 : }
1471 : }
1472 :
1473 331808 : ASMJIT_PROPAGATE(lra.allocInst(inst));
1474 331808 : if (inst->type() == NodeType::kInvoke)
1475 9639 : ASMJIT_PROPAGATE(emitPreCall(inst->as<InvokeNode>()));
1476 : else
1477 322169 : ASMJIT_PROPAGATE(lra.spillAfterAllocation(inst));
1478 : }
1479 : node = next;
1480 : }
1481 :
1482 54984 : if (consecutive) {
1483 27492 : BaseNode* prev = afterLast ? afterLast->prev() : cc()->lastNode();
1484 27492 : cc()->_setCursor(unconditionalJump ? prev->prev() : prev);
1485 :
1486 27492 : if (consecutive->hasEntryAssignment()) {
1487 0 : ASMJIT_PROPAGATE(lra.switchToAssignment(consecutive->entryPhysToWorkMap(), consecutive->liveIn(), consecutive->isAllocated(), false));
1488 : }
1489 : else {
1490 27492 : ASMJIT_PROPAGATE(lra.spillRegsBeforeEntry(consecutive));
1491 27492 : ASMJIT_PROPAGATE(setBlockEntryAssignment(consecutive, block, lra._curAssignment));
1492 27492 : lra._curAssignment.copyFrom(consecutive->entryPhysToWorkMap());
1493 : }
1494 : }
1495 :
1496 : // Important as the local allocator can insert instructions before
1497 : // and after any instruction within the basic block.
1498 : block->setFirst(beforeFirst->next());
1499 54984 : block->setLast(afterLast ? afterLast->prev() : cc()->lastNode());
1500 :
1501 54984 : if (--blocksRemaining == 0)
1502 : break;
1503 :
1504 : // Switch to the next consecutive block, if any.
1505 27492 : if (consecutive) {
1506 : block = consecutive;
1507 27492 : if (!block->isAllocated())
1508 27492 : continue;
1509 : }
1510 :
1511 : // Get the next block.
1512 : for (;;) {
1513 0 : if (++blockId >= blockCount())
1514 : blockId = 0;
1515 :
1516 0 : block = _blocks[blockId];
1517 0 : if (!block->isReachable() || block->isAllocated() || !block->hasEntryAssignment())
1518 : continue;
1519 :
1520 : break;
1521 : }
1522 :
1523 : // If we switched to some block we have to update the local allocator.
1524 0 : lra.replaceAssignment(block->entryPhysToWorkMap());
1525 : }
1526 :
1527 : _clobberedRegs.op<Support::Or>(lra._clobberedRegs);
1528 : return kErrorOk;
1529 : }
1530 :
1531 54984 : Error BaseRAPass::setBlockEntryAssignment(RABlock* block, const RABlock* fromBlock, const RAAssignment& fromAssignment) noexcept {
1532 54984 : if (block->hasSharedAssignmentId()) {
1533 : uint32_t sharedAssignmentId = block->sharedAssignmentId();
1534 :
1535 : // Shouldn't happen. Entry assignment of a block that has a shared-state will assign to all blocks
1536 : // with the same sharedAssignmentId. It's a bug if the shared state has been already assigned.
1537 0 : if (!_sharedAssignments[sharedAssignmentId].empty())
1538 : return DebugUtils::errored(kErrorInvalidState);
1539 :
1540 0 : return setSharedAssignment(sharedAssignmentId, fromAssignment);
1541 : }
1542 :
1543 54984 : PhysToWorkMap* physToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap());
1544 54984 : if (ASMJIT_UNLIKELY(!physToWorkMap))
1545 : return DebugUtils::errored(kErrorOutOfMemory);
1546 :
1547 : block->setEntryAssignment(physToWorkMap);
1548 :
1549 : // True if this is the first (entry) block, nothing to do in this case.
1550 54984 : if (block == fromBlock) {
1551 : // Entry block should never have a shared state.
1552 27492 : if (block->hasSharedAssignmentId())
1553 : return DebugUtils::errored(kErrorInvalidState);
1554 :
1555 27492 : return kErrorOk;
1556 : }
1557 :
1558 : const ZoneBitVector& liveOut = fromBlock->liveOut();
1559 : const ZoneBitVector& liveIn = block->liveIn();
1560 :
1561 : // It's possible that `fromBlock` has LIVE-OUT regs that `block` doesn't
1562 : // have in LIVE-IN, these have to be unassigned.
1563 : {
1564 27492 : ZoneBitVector::ForEachBitOp<Support::AndNot> it(liveOut, liveIn);
1565 54984 : while (it.hasNext()) {
1566 0 : uint32_t workId = uint32_t(it.next());
1567 : RAWorkReg* workReg = workRegById(workId);
1568 :
1569 : RegGroup group = workReg->group();
1570 : uint32_t physId = fromAssignment.workToPhysId(group, workId);
1571 :
1572 0 : if (physId != RAAssignment::kPhysNone)
1573 0 : physToWorkMap->unassign(group, physId, _physRegIndex.get(group) + physId);
1574 : }
1575 : }
1576 :
1577 27492 : return blockEntryAssigned(physToWorkMap);
1578 : }
1579 :
1580 0 : Error BaseRAPass::setSharedAssignment(uint32_t sharedAssignmentId, const RAAssignment& fromAssignment) noexcept {
1581 : ASMJIT_ASSERT(_sharedAssignments[sharedAssignmentId].empty());
1582 :
1583 0 : PhysToWorkMap* physToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap());
1584 0 : if (ASMJIT_UNLIKELY(!physToWorkMap))
1585 : return DebugUtils::errored(kErrorOutOfMemory);
1586 :
1587 0 : _sharedAssignments[sharedAssignmentId].assignPhysToWorkMap(physToWorkMap);
1588 :
1589 0 : ZoneBitVector& sharedLiveIn = _sharedAssignments[sharedAssignmentId]._liveIn;
1590 0 : ASMJIT_PROPAGATE(sharedLiveIn.resize(allocator(), workRegCount()));
1591 :
1592 0 : Support::Array<uint32_t, Globals::kNumVirtGroups> sharedAssigned {};
1593 0 : for (RABlock* block : blocks()) {
1594 0 : if (block->sharedAssignmentId() == sharedAssignmentId) {
1595 : ASMJIT_ASSERT(!block->hasEntryAssignment());
1596 :
1597 0 : PhysToWorkMap* entryPhysToWorkMap = clonePhysToWorkMap(fromAssignment.physToWorkMap());
1598 0 : if (ASMJIT_UNLIKELY(!entryPhysToWorkMap))
1599 : return DebugUtils::errored(kErrorOutOfMemory);
1600 :
1601 : block->setEntryAssignment(entryPhysToWorkMap);
1602 :
1603 : const ZoneBitVector& liveIn = block->liveIn();
1604 : sharedLiveIn.or_(liveIn);
1605 :
1606 0 : for (RegGroup group : RegGroupVirtValues{}) {
1607 0 : sharedAssigned[group] |= entryPhysToWorkMap->assigned[group];
1608 :
1609 : uint32_t physBaseIndex = _physRegIndex.get(group);
1610 : Support::BitWordIterator<RegMask> it(entryPhysToWorkMap->assigned[group]);
1611 :
1612 0 : while (it.hasNext()) {
1613 : uint32_t physId = it.next();
1614 0 : uint32_t workId = entryPhysToWorkMap->workIds[physBaseIndex + physId];
1615 :
1616 0 : if (!liveIn.bitAt(workId))
1617 0 : entryPhysToWorkMap->unassign(group, physId, physBaseIndex + physId);
1618 : }
1619 : }
1620 : }
1621 : }
1622 :
1623 0 : for (RegGroup group : RegGroupVirtValues{}) {
1624 : uint32_t physBaseIndex = _physRegIndex.get(group);
1625 0 : Support::BitWordIterator<RegMask> it(_availableRegs[group] & ~sharedAssigned[group]);
1626 :
1627 0 : while (it.hasNext()) {
1628 : uint32_t physId = it.next();
1629 0 : if (Support::bitTest(physToWorkMap->assigned[group], physId))
1630 0 : physToWorkMap->unassign(group, physId, physBaseIndex + physId);
1631 : }
1632 : }
1633 :
1634 0 : return blockEntryAssigned(physToWorkMap);
1635 : }
1636 :
1637 27492 : Error BaseRAPass::blockEntryAssigned(const PhysToWorkMap* physToWorkMap) noexcept {
1638 : // Complex allocation strategy requires to record register assignments upon block entry (or per shared state).
1639 137460 : for (RegGroup group : RegGroupVirtValues{}) {
1640 109968 : if (!_strategy[group].isComplex())
1641 : continue;
1642 :
1643 1955 : uint32_t physBaseIndex = _physRegIndex[group];
1644 1955 : Support::BitWordIterator<RegMask> it(physToWorkMap->assigned[group]);
1645 :
1646 1955 : while (it.hasNext()) {
1647 : uint32_t physId = it.next();
1648 0 : uint32_t workId = physToWorkMap->workIds[physBaseIndex + physId];
1649 :
1650 : RAWorkReg* workReg = workRegById(workId);
1651 : workReg->addAllocatedMask(Support::bitMask(physId));
1652 : }
1653 : }
1654 :
1655 27492 : return kErrorOk;
1656 : }
1657 :
1658 : // BaseRAPass - Allocation - Utilities
1659 : // ===================================
1660 :
1661 0 : Error BaseRAPass::useTemporaryMem(BaseMem& out, uint32_t size, uint32_t alignment) noexcept {
1662 : ASMJIT_ASSERT(alignment <= 64);
1663 :
1664 0 : if (_temporaryMem.isNone()) {
1665 0 : ASMJIT_PROPAGATE(cc()->_newStack(&_temporaryMem.as<BaseMem>(), size, alignment));
1666 : }
1667 : else {
1668 : ASMJIT_ASSERT(_temporaryMem.as<BaseMem>().isRegHome());
1669 :
1670 : uint32_t virtId = _temporaryMem.as<BaseMem>().baseId();
1671 : VirtReg* virtReg = cc()->virtRegById(virtId);
1672 :
1673 0 : cc()->setStackSize(virtId, Support::max(virtReg->virtSize(), size),
1674 : Support::max(virtReg->alignment(), alignment));
1675 : }
1676 :
1677 : out = _temporaryMem.as<BaseMem>();
1678 0 : return kErrorOk;
1679 : }
1680 :
1681 : // BaseRAPass - Allocation - Prolog & Epilog
1682 : // =========================================
1683 :
1684 27492 : Error BaseRAPass::updateStackFrame() noexcept {
1685 : // Update some StackFrame information that we updated during allocation. The only information we don't have at the
1686 : // moment is final local stack size, which is calculated last.
1687 : FuncFrame& frame = func()->frame();
1688 137460 : for (RegGroup group : RegGroupVirtValues{})
1689 109968 : frame.addDirtyRegs(group, _clobberedRegs[group]);
1690 : frame.setLocalStackAlignment(_stackAllocator.alignment());
1691 :
1692 : // If there are stack arguments that are not assigned to registers upon entry and the function doesn't require
1693 : // dynamic stack alignment we keep these arguments where they are. This will also mark all stack slots that match
1694 : // these arguments as allocated.
1695 27492 : if (_numStackArgsToStackSlots)
1696 0 : ASMJIT_PROPAGATE(_markStackArgsToKeep());
1697 :
1698 : // Calculate offsets of all stack slots and update StackSize to reflect the calculated local stack size.
1699 27492 : ASMJIT_PROPAGATE(_stackAllocator.calculateStackFrame());
1700 : frame.setLocalStackSize(_stackAllocator.stackSize());
1701 :
1702 : // Update the stack frame based on `_argsAssignment` and finalize it. Finalization means to apply final calculation
1703 : // to the stack layout.
1704 27492 : ASMJIT_PROPAGATE(_argsAssignment.updateFuncFrame(frame));
1705 27492 : ASMJIT_PROPAGATE(frame.finalize());
1706 :
1707 : // StackAllocator allocates all stots starting from [0], adjust them when necessary.
1708 27492 : if (frame.localStackOffset() != 0)
1709 0 : ASMJIT_PROPAGATE(_stackAllocator.adjustSlotOffsets(int32_t(frame.localStackOffset())));
1710 :
1711 : // Again, if there are stack arguments allocated in function's stack we have to handle them. This handles all cases
1712 : // (either regular or dynamic stack alignment).
1713 27492 : if (_numStackArgsToStackSlots)
1714 0 : ASMJIT_PROPAGATE(_updateStackArgs());
1715 :
1716 : return kErrorOk;
1717 : }
1718 :
1719 0 : Error BaseRAPass::_markStackArgsToKeep() noexcept {
1720 : FuncFrame& frame = func()->frame();
1721 0 : bool hasSAReg = frame.hasPreservedFP() || !frame.hasDynamicAlignment();
1722 :
1723 : RAWorkRegs& workRegs = _workRegs;
1724 : uint32_t numWorkRegs = workRegCount();
1725 :
1726 0 : for (uint32_t workId = 0; workId < numWorkRegs; workId++) {
1727 0 : RAWorkReg* workReg = workRegs[workId];
1728 0 : if (workReg->hasFlag(RAWorkRegFlags::kStackArgToStack)) {
1729 : ASMJIT_ASSERT(workReg->hasArgIndex());
1730 0 : const FuncValue& srcArg = _func->detail().arg(workReg->argIndex());
1731 :
1732 : // If the register doesn't have stack slot then we failed. It doesn't make much sense as it was marked as
1733 : // `kFlagStackArgToStack`, which requires the WorkReg was live-in upon function entry.
1734 : RAStackSlot* slot = workReg->stackSlot();
1735 0 : if (ASMJIT_UNLIKELY(!slot))
1736 : return DebugUtils::errored(kErrorInvalidState);
1737 :
1738 0 : if (hasSAReg && srcArg.isStack() && !srcArg.isIndirect()) {
1739 : uint32_t typeSize = TypeUtils::sizeOf(srcArg.typeId());
1740 0 : if (typeSize == slot->size()) {
1741 : slot->addFlags(RAStackSlot::kFlagStackArg);
1742 0 : continue;
1743 : }
1744 : }
1745 :
1746 : // NOTE: Update StackOffset here so when `_argsAssignment.updateFuncFrame()` is called it will take into
1747 : // consideration moving to stack slots. Without this we may miss some scratch registers later.
1748 0 : FuncValue& dstArg = _argsAssignment.arg(workReg->argIndex(), workReg->argValueIndex());
1749 : dstArg.assignStackOffset(0);
1750 : }
1751 : }
1752 :
1753 : return kErrorOk;
1754 : }
1755 :
1756 0 : Error BaseRAPass::_updateStackArgs() noexcept {
1757 : FuncFrame& frame = func()->frame();
1758 : RAWorkRegs& workRegs = _workRegs;
1759 : uint32_t numWorkRegs = workRegCount();
1760 :
1761 0 : for (uint32_t workId = 0; workId < numWorkRegs; workId++) {
1762 0 : RAWorkReg* workReg = workRegs[workId];
1763 0 : if (workReg->hasFlag(RAWorkRegFlags::kStackArgToStack)) {
1764 : ASMJIT_ASSERT(workReg->hasArgIndex());
1765 : RAStackSlot* slot = workReg->stackSlot();
1766 :
1767 0 : if (ASMJIT_UNLIKELY(!slot))
1768 : return DebugUtils::errored(kErrorInvalidState);
1769 :
1770 0 : if (slot->isStackArg()) {
1771 0 : const FuncValue& srcArg = _func->detail().arg(workReg->argIndex());
1772 0 : if (frame.hasPreservedFP()) {
1773 : slot->setBaseRegId(_fp.id());
1774 0 : slot->setOffset(int32_t(frame.saOffsetFromSA()) + srcArg.stackOffset());
1775 : }
1776 : else {
1777 0 : slot->setOffset(int32_t(frame.saOffsetFromSP()) + srcArg.stackOffset());
1778 : }
1779 : }
1780 : else {
1781 0 : FuncValue& dstArg = _argsAssignment.arg(workReg->argIndex(), workReg->argValueIndex());
1782 : dstArg.setStackOffset(slot->offset());
1783 : }
1784 : }
1785 : }
1786 :
1787 : return kErrorOk;
1788 : }
1789 :
1790 27492 : Error BaseRAPass::insertPrologEpilog() noexcept {
1791 27492 : FuncFrame& frame = _func->frame();
1792 :
1793 : cc()->_setCursor(func());
1794 27492 : ASMJIT_PROPAGATE(cc()->emitProlog(frame));
1795 27492 : ASMJIT_PROPAGATE(_iEmitHelper->emitArgsAssignment(frame, _argsAssignment));
1796 :
1797 : cc()->_setCursor(func()->exitNode());
1798 27492 : ASMJIT_PROPAGATE(cc()->emitEpilog(frame));
1799 :
1800 : return kErrorOk;
1801 : }
1802 :
1803 : // BaseRAPass - Rewriter
1804 : // =====================
1805 :
1806 27492 : Error BaseRAPass::rewrite() noexcept {
1807 27492 : return _rewrite(_func, _stop);
1808 : }
1809 :
1810 : // BaseRAPass - Logging
1811 : // ====================
1812 :
1813 : #ifndef ASMJIT_NO_LOGGING
1814 0 : static void RAPass_formatLiveness(BaseRAPass* pass, String& sb, const RAInst* raInst) noexcept {
1815 : const RATiedReg* tiedRegs = raInst->tiedRegs();
1816 : uint32_t tiedCount = raInst->tiedCount();
1817 :
1818 0 : for (uint32_t i = 0; i < tiedCount; i++) {
1819 0 : const RATiedReg& tiedReg = tiedRegs[i];
1820 :
1821 0 : if (i != 0)
1822 : sb.append(' ');
1823 :
1824 : sb.appendFormat("%s{", pass->workRegById(tiedReg.workId())->name());
1825 0 : sb.append(tiedReg.isReadWrite() ? 'X' :
1826 : tiedReg.isRead() ? 'R' :
1827 : tiedReg.isWrite() ? 'W' : '?');
1828 :
1829 0 : if (tiedReg.isLeadConsecutive())
1830 0 : sb.appendFormat("|Lead[%u]", tiedReg.consecutiveData() + 1u);
1831 :
1832 0 : if (tiedReg.hasUseId())
1833 : sb.appendFormat("|Use=%u", tiedReg.useId());
1834 0 : else if (tiedReg.isUse())
1835 : sb.append("|Use");
1836 :
1837 0 : if (tiedReg.isUseConsecutive() && !tiedReg.isLeadConsecutive())
1838 : sb.appendFormat("+%u", tiedReg.consecutiveData());
1839 :
1840 0 : if (tiedReg.hasOutId())
1841 : sb.appendFormat("|Out=%u", tiedReg.outId());
1842 0 : else if (tiedReg.isOut())
1843 : sb.append("|Out");
1844 :
1845 0 : if (tiedReg.isOutConsecutive() && !tiedReg.isLeadConsecutive())
1846 : sb.appendFormat("+%u", tiedReg.consecutiveData());
1847 :
1848 0 : if (tiedReg.isLast())
1849 : sb.append("|Last");
1850 :
1851 0 : if (tiedReg.isKill())
1852 : sb.append("|Kill");
1853 :
1854 : sb.append("}");
1855 : }
1856 0 : }
1857 :
1858 0 : ASMJIT_FAVOR_SIZE Error BaseRAPass::annotateCode() noexcept {
1859 0 : StringTmp<1024> sb;
1860 :
1861 0 : for (const RABlock* block : _blocks) {
1862 : BaseNode* node = block->first();
1863 0 : if (!node) continue;
1864 :
1865 : BaseNode* last = block->last();
1866 : for (;;) {
1867 0 : sb.clear();
1868 0 : Formatter::formatNode(sb, _formatOptions, cc(), node);
1869 :
1870 0 : if (hasDiagnosticOption(DiagnosticOptions::kRADebugLiveness) && node->isInst() && node->hasPassData()) {
1871 : const RAInst* raInst = node->passData<RAInst>();
1872 0 : if (raInst->tiedCount() > 0) {
1873 0 : sb.padEnd(40);
1874 0 : sb.append(" | ");
1875 0 : RAPass_formatLiveness(this, sb, raInst);
1876 : }
1877 : }
1878 :
1879 0 : node->setInlineComment(static_cast<char*>(cc()->_dataZone.dup(sb.data(), sb.size(), true)));
1880 0 : if (node == last)
1881 : break;
1882 : node = node->next();
1883 0 : }
1884 : }
1885 :
1886 0 : return kErrorOk;
1887 : }
1888 :
1889 0 : ASMJIT_FAVOR_SIZE Error BaseRAPass::_dumpBlockIds(String& sb, const RABlocks& blocks) noexcept {
1890 0 : for (uint32_t i = 0, size = blocks.size(); i < size; i++) {
1891 0 : const RABlock* block = blocks[i];
1892 0 : if (i != 0)
1893 0 : ASMJIT_PROPAGATE(sb.appendFormat(", #%u", block->blockId()));
1894 : else
1895 0 : ASMJIT_PROPAGATE(sb.appendFormat("#%u", block->blockId()));
1896 : }
1897 : return kErrorOk;
1898 : }
1899 :
1900 0 : ASMJIT_FAVOR_SIZE Error BaseRAPass::_dumpBlockLiveness(String& sb, const RABlock* block) noexcept {
1901 0 : for (uint32_t liveType = 0; liveType < RABlock::kLiveCount; liveType++) {
1902 0 : const char* bitsName = liveType == RABlock::kLiveIn ? "IN " :
1903 : liveType == RABlock::kLiveOut ? "OUT " :
1904 : liveType == RABlock::kLiveGen ? "GEN " : "KILL";
1905 :
1906 0 : const ZoneBitVector& bits = block->_liveBits[liveType];
1907 : uint32_t size = bits.size();
1908 : ASMJIT_ASSERT(size <= workRegCount());
1909 :
1910 : uint32_t n = 0;
1911 0 : for (uint32_t workId = 0; workId < size; workId++) {
1912 0 : if (bits.bitAt(workId)) {
1913 : RAWorkReg* wReg = workRegById(workId);
1914 :
1915 0 : if (!n)
1916 0 : sb.appendFormat(" %s [", bitsName);
1917 : else
1918 0 : sb.append(", ");
1919 :
1920 0 : sb.append(wReg->name());
1921 0 : n++;
1922 : }
1923 : }
1924 :
1925 0 : if (n)
1926 0 : sb.append("]\n");
1927 : }
1928 :
1929 0 : return kErrorOk;
1930 : }
1931 :
1932 0 : ASMJIT_FAVOR_SIZE Error BaseRAPass::_dumpLiveSpans(String& sb) noexcept {
1933 : uint32_t numWorkRegs = _workRegs.size();
1934 0 : uint32_t maxSize = _maxWorkRegNameSize;
1935 :
1936 0 : for (uint32_t workId = 0; workId < numWorkRegs; workId++) {
1937 0 : RAWorkReg* workReg = _workRegs[workId];
1938 :
1939 0 : sb.append(" ");
1940 :
1941 : size_t oldSize = sb.size();
1942 0 : sb.append(workReg->name());
1943 0 : sb.padEnd(oldSize + maxSize);
1944 :
1945 : RALiveStats& stats = workReg->liveStats();
1946 0 : sb.appendFormat(" {id:%04u width: %-4u freq: %0.4f priority=%0.4f}",
1947 0 : workReg->virtId(),
1948 0 : stats.width(),
1949 0 : stats.freq(),
1950 0 : stats.priority());
1951 0 : sb.append(": ");
1952 :
1953 : LiveRegSpans& liveSpans = workReg->liveSpans();
1954 0 : for (uint32_t x = 0; x < liveSpans.size(); x++) {
1955 : const LiveRegSpan& liveSpan = liveSpans[x];
1956 0 : if (x)
1957 0 : sb.append(", ");
1958 0 : sb.appendFormat("[%u:%u]", liveSpan.a, liveSpan.b);
1959 : }
1960 :
1961 0 : sb.append('\n');
1962 : }
1963 :
1964 0 : return kErrorOk;
1965 : }
1966 : #endif
1967 :
1968 : ASMJIT_END_NAMESPACE
1969 :
1970 : #endif // !ASMJIT_NO_COMPILER
1971 :
1972 : #endif // __PLUMED_HAS_ASMJIT
|