LCOV - code coverage report
Current view: top level - asmjit - regalloc.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 114 241 47.3 %
Date: 2024-10-18 14:00:27 Functions: 9 13 69.2 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : Copyright (c) 2008-2017, Petr Kobalicek
       3             : 
       4             : This software is provided 'as-is', without any express or implied
       5             : warranty. In no event will the authors be held liable for any damages
       6             : arising from the use of this software.
       7             : 
       8             : Permission is granted to anyone to use this software for any purpose,
       9             : including commercial applications, and to alter it and redistribute it
      10             : freely, subject to the following restrictions:
      11             : 
      12             : 1. The origin of this software must not be misrepresented; you must not
      13             :    claim that you wrote the original software. If you use this software
      14             :    in a product, an acknowledgment in the product documentation would be
      15             :    appreciated but is not required.
      16             : 2. Altered source versions must be plainly marked as such, and must not be
      17             :    misrepresented as being the original software.
      18             : 3. This notice may not be removed or altered from any source distribution.
      19             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      20             : #ifdef __PLUMED_HAS_ASMJIT
      21             : #pragma GCC diagnostic push
      22             : #pragma GCC diagnostic ignored "-Wpedantic"
      23             : // [AsmJit]
      24             : // Complete x86/x64 JIT and Remote Assembler for C++.
      25             : //
      26             : // [License]
      27             : // Zlib - See LICENSE.md file in the package.
      28             : 
      29             : // [Export]
      30             : #define ASMJIT_EXPORTS
      31             : 
      32             : // [Guard]
      33             : #include "./asmjit_build.h"
      34             : #if !defined(ASMJIT_DISABLE_COMPILER)
      35             : 
      36             : // [Dependencies]
      37             : #include "./regalloc_p.h"
      38             : #include "./utils.h"
      39             : 
      40             : // [Api-Begin]
      41             : #include "./asmjit_apibegin.h"
      42             : 
      43             : namespace PLMD {
      44             : namespace asmjit {
      45             : 
      46             : // ============================================================================
      47             : // [asmjit::RAPass - Construction / Destruction]
      48             : // ============================================================================
      49             : 
      50       32111 : RAPass::RAPass() noexcept :
      51             :   CBPass("RA"),
      52       32111 :   _varMapToVaListOffset(0) {}
      53           0 : RAPass::~RAPass() noexcept {}
      54             : 
      55             : // ============================================================================
      56             : // [asmjit::RAPass - Interface]
      57             : // ============================================================================
      58             : 
      59       32111 : Error RAPass::process(Zone* zone) noexcept {
      60       32111 :   _zone = zone;
      61       32111 :   _heap.reset(zone);
      62       32111 :   _emitComments = (cb()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) != 0;
      63             : 
      64             :   Error err = kErrorOk;
      65             :   CBNode* node = cc()->getFirstNode();
      66       32111 :   if (!node) return err;
      67             : 
      68             :   do {
      69       32111 :     if (node->getType() == CBNode::kNodeFunc) {
      70             :       CCFunc* func = static_cast<CCFunc*>(node);
      71             :       node = func->getEnd();
      72             : 
      73       32111 :       err = compile(func);
      74       32111 :       if (err) break;
      75             :     }
      76             : 
      77             :     // Find a function by skipping all nodes that are not `kNodeFunc`.
      78             :     do {
      79             :       node = node->getNext();
      80       32111 :     } while (node && node->getType() != CBNode::kNodeFunc);
      81       32111 :   } while (node);
      82             : 
      83       32111 :   _heap.reset(nullptr);
      84       32111 :   _zone = nullptr;
      85       32111 :   return err;
      86             : }
      87             : 
      88       32111 : Error RAPass::compile(CCFunc* func) noexcept {
      89       32111 :   ASMJIT_PROPAGATE(prepare(func));
      90             : 
      91             :   Error err;
      92             :   do {
      93       32111 :     err = fetch();
      94       32111 :     if (err) break;
      95             : 
      96       32111 :     err = removeUnreachableCode();
      97       32111 :     if (err) break;
      98             : 
      99       32111 :     err = livenessAnalysis();
     100       32111 :     if (err) break;
     101             : 
     102             : #if !defined(ASMJIT_DISABLE_LOGGING)
     103       32111 :     if (cc()->getGlobalOptions() & CodeEmitter::kOptionLoggingEnabled) {
     104           0 :       err = annotate();
     105           0 :       if (err) break;
     106             :     }
     107             : #endif // !ASMJIT_DISABLE_LOGGING
     108             : 
     109       32111 :     err = translate();
     110             :   } while (false);
     111             : 
     112       32111 :   cleanup();
     113             : 
     114             :   // We alter the compiler cursor, because it doesn't make sense to reference
     115             :   // it after compilation - some nodes may disappear and it's forbidden to add
     116             :   // new code after the compilation is done.
     117             :   cc()->_setCursor(nullptr);
     118       32111 :   return err;
     119             : }
     120             : 
     121       32111 : Error RAPass::prepare(CCFunc* func) noexcept {
     122             :   CBNode* end = func->getEnd();
     123             : 
     124       32111 :   _func = func;
     125       32111 :   _stop = end->getNext();
     126             : 
     127             :   _unreachableList.reset();
     128             :   _returningList.reset();
     129             :   _jccList.reset();
     130             :   _contextVd.reset();
     131             : 
     132       32111 :   _memVarCells = nullptr;
     133       32111 :   _memStackCells = nullptr;
     134             : 
     135       32111 :   _mem1ByteVarsUsed = 0;
     136       32111 :   _mem2ByteVarsUsed = 0;
     137       32111 :   _mem4ByteVarsUsed = 0;
     138       32111 :   _mem8ByteVarsUsed = 0;
     139       32111 :   _mem16ByteVarsUsed = 0;
     140       32111 :   _mem32ByteVarsUsed = 0;
     141       32111 :   _mem64ByteVarsUsed = 0;
     142       32111 :   _memStackCellsUsed = 0;
     143             : 
     144       32111 :   _memMaxAlign = 0;
     145       32111 :   _memVarTotal = 0;
     146       32111 :   _memStackTotal = 0;
     147       32111 :   _memAllTotal = 0;
     148       32111 :   _annotationLength = 12;
     149             : 
     150       32111 :   return kErrorOk;
     151             : }
     152             : 
     153       32111 : void RAPass::cleanup() noexcept {
     154             :   VirtReg** virtArray = _contextVd.getData();
     155             :   size_t virtCount = _contextVd.getLength();
     156             : 
     157      349923 :   for (size_t i = 0; i < virtCount; i++) {
     158      317812 :     VirtReg* vreg = virtArray[i];
     159      317812 :     vreg->_raId = kInvalidValue;
     160             :     vreg->resetPhysId();
     161             :   }
     162             : 
     163             :   _contextVd.reset();
     164       32111 : }
     165             : 
     166             : // ============================================================================
     167             : // [asmjit::RAPass - Mem]
     168             : // ============================================================================
     169             : 
     170             : static ASMJIT_INLINE uint32_t RAGetDefaultAlignment(uint32_t size) {
     171           0 :   if (size > 32)
     172             :     return 64;
     173           0 :   else if (size > 16)
     174             :     return 32;
     175           0 :   else if (size > 8)
     176             :     return 16;
     177           0 :   else if (size > 4)
     178             :     return 8;
     179           0 :   else if (size > 2)
     180             :     return 4;
     181           0 :   else if (size > 1)
     182             :     return 2;
     183             :   else
     184           0 :     return 1;
     185             : }
     186             : 
     187       39976 : RACell* RAPass::_newVarCell(VirtReg* vreg) {
     188             :   ASMJIT_ASSERT(vreg->_memCell == nullptr);
     189             : 
     190             :   RACell* cell;
     191       39976 :   uint32_t size = vreg->getSize();
     192             : 
     193       39976 :   if (vreg->isStack()) {
     194           0 :     cell = _newStackCell(size, vreg->getAlignment());
     195           0 :     if (ASMJIT_UNLIKELY(!cell)) return nullptr;
     196             :   }
     197             :   else {
     198       39976 :     cell = static_cast<RACell*>(_zone->alloc(sizeof(RACell)));
     199       39976 :     if (!cell) goto _NoMemory;
     200             : 
     201       39976 :     cell->next = _memVarCells;
     202       39976 :     cell->offset = 0;
     203       39976 :     cell->size = size;
     204       39976 :     cell->alignment = size;
     205             : 
     206       39976 :     _memVarCells = cell;
     207       39976 :     _memMaxAlign = std::max<uint32_t>(_memMaxAlign, size);
     208       39976 :     _memVarTotal += size;
     209             : 
     210       39976 :     switch (size) {
     211           0 :       case  1: _mem1ByteVarsUsed++ ; break;
     212           0 :       case  2: _mem2ByteVarsUsed++ ; break;
     213           0 :       case  4: _mem4ByteVarsUsed++ ; break;
     214       39976 :       case  8: _mem8ByteVarsUsed++ ; break;
     215           0 :       case 16: _mem16ByteVarsUsed++; break;
     216           0 :       case 32: _mem32ByteVarsUsed++; break;
     217           0 :       case 64: _mem64ByteVarsUsed++; break;
     218             : 
     219           0 :       default:
     220           0 :         ASMJIT_NOT_REACHED();
     221             :     }
     222             :   }
     223             : 
     224       39976 :   vreg->_memCell = cell;
     225       39976 :   return cell;
     226             : 
     227             : _NoMemory:
     228           0 :   cc()->setLastError(DebugUtils::errored(kErrorNoHeapMemory));
     229             :   return nullptr;
     230             : }
     231             : 
     232           0 : RACell* RAPass::_newStackCell(uint32_t size, uint32_t alignment) {
     233           0 :   RACell* cell = static_cast<RACell*>(_zone->alloc(sizeof(RACell)));
     234           0 :   if (ASMJIT_UNLIKELY(!cell)) return nullptr;
     235             : 
     236           0 :   if (alignment == 0)
     237           0 :     alignment = RAGetDefaultAlignment(size);
     238             : 
     239           0 :   if (alignment > 64)
     240           0 :     alignment = 64;
     241             : 
     242             :   ASMJIT_ASSERT(Utils::isPowerOf2(alignment));
     243           0 :   size = Utils::alignTo<uint32_t>(size, alignment);
     244             : 
     245             :   // Insert it sorted according to the alignment and size.
     246             :   {
     247           0 :     RACell** pPrev = &_memStackCells;
     248           0 :     RACell* cur = *pPrev;
     249             : 
     250           0 :     while (cur && ((cur->alignment > alignment) || (cur->alignment == alignment && cur->size > size))) {
     251           0 :       pPrev = &cur->next;
     252           0 :       cur = *pPrev;
     253             :     }
     254             : 
     255           0 :     cell->next = cur;
     256           0 :     cell->offset = 0;
     257           0 :     cell->size = size;
     258           0 :     cell->alignment = alignment;
     259             : 
     260           0 :     *pPrev = cell;
     261           0 :     _memStackCellsUsed++;
     262             : 
     263           0 :     _memMaxAlign = std::max<uint32_t>(_memMaxAlign, alignment);
     264           0 :     _memStackTotal += size;
     265             :   }
     266             : 
     267           0 :   return cell;
     268             : }
     269             : 
     270       32111 : Error RAPass::resolveCellOffsets() {
     271       32111 :   RACell* varCell = _memVarCells;
     272       32111 :   RACell* stackCell = _memStackCells;
     273             : 
     274             :   uint32_t pos64 = 0;
     275       32111 :   uint32_t pos32 = pos64 + _mem64ByteVarsUsed * 64;
     276       32111 :   uint32_t pos16 = pos32 + _mem32ByteVarsUsed * 32;
     277       32111 :   uint32_t pos8  = pos16 + _mem16ByteVarsUsed * 16;
     278       32111 :   uint32_t pos4  = pos8  + _mem8ByteVarsUsed  * 8 ;
     279       32111 :   uint32_t pos2  = pos4  + _mem4ByteVarsUsed  * 4 ;
     280       32111 :   uint32_t pos1  = pos2  + _mem2ByteVarsUsed  * 2 ;
     281             : 
     282             :   // Assign home slots.
     283       72087 :   while (varCell) {
     284       39976 :     uint32_t size = varCell->size;
     285             :     uint32_t offset = 0;
     286             : 
     287       39976 :     switch (size) {
     288           0 :       case  1: offset = pos1 ; pos1  += 1 ; break;
     289           0 :       case  2: offset = pos2 ; pos2  += 2 ; break;
     290           0 :       case  4: offset = pos4 ; pos4  += 4 ; break;
     291       39976 :       case  8: offset = pos8 ; pos8  += 8 ; break;
     292           0 :       case 16: offset = pos16; pos16 += 16; break;
     293           0 :       case 32: offset = pos32; pos32 += 32; break;
     294           0 :       case 64: offset = pos64; pos64 += 64; break;
     295             : 
     296           0 :       default:
     297           0 :         ASMJIT_NOT_REACHED();
     298             :     }
     299             : 
     300       39976 :     varCell->offset = static_cast<int32_t>(offset);
     301       39976 :     varCell = varCell->next;
     302             :   }
     303             : 
     304             :   // Assign stack slots.
     305       32111 :   uint32_t stackPos = pos1 + _mem1ByteVarsUsed;
     306       32111 :   while (stackCell) {
     307           0 :     uint32_t size = stackCell->size;
     308           0 :     uint32_t alignment = stackCell->alignment;
     309             :     ASMJIT_ASSERT(alignment != 0 && Utils::isPowerOf2(alignment));
     310             : 
     311             :     stackPos = Utils::alignTo(stackPos, alignment);
     312           0 :     stackCell->offset = stackPos;
     313           0 :     stackCell = stackCell->next;
     314             : 
     315           0 :     stackPos += size;
     316             :   }
     317             : 
     318       32111 :   _memAllTotal = stackPos;
     319       32111 :   return kErrorOk;
     320             : }
     321             : 
     322             : // ============================================================================
     323             : // [asmjit::RAPass - RemoveUnreachableCode]
     324             : // ============================================================================
     325             : 
     326       32111 : Error RAPass::removeUnreachableCode() {
     327             :   ZoneList<CBNode*>::Link* link = _unreachableList.getFirst();
     328             :   CBNode* stop = getStop();
     329             : 
     330       64222 :   while (link) {
     331             :     CBNode* node = link->getValue();
     332       32111 :     if (node && node->getPrev() && node != stop) {
     333             :       // Locate all unreachable nodes.
     334             :       CBNode* first = node;
     335             :       do {
     336       32111 :         if (node->hasPassData()) break;
     337             :         node = node->getNext();
     338           0 :       } while (node != stop);
     339             : 
     340             :       // Remove unreachable nodes that are neither informative nor directives.
     341       32111 :       if (node != first) {
     342             :         CBNode* end = node;
     343             :         node = first;
     344             : 
     345             :         // NOTE: The strategy is as follows:
     346             :         // 1. The algorithm removes everything until it finds a first label.
     347             :         // 2. After the first label is found it removes only removable nodes.
     348             :         bool removeEverything = true;
     349             :         do {
     350             :           CBNode* next = node->getNext();
     351             :           bool remove = node->isRemovable();
     352             : 
     353           0 :           if (!remove) {
     354           0 :             if (node->isLabel())
     355             :               removeEverything = false;
     356             :             remove = removeEverything;
     357             :           }
     358             : 
     359           0 :           if (remove)
     360           0 :             cc()->removeNode(node);
     361             : 
     362             :           node = next;
     363           0 :         } while (node != end);
     364             :       }
     365             :     }
     366             : 
     367             :     link = link->getNext();
     368             :   }
     369             : 
     370       32111 :   return kErrorOk;
     371             : }
     372             : 
     373             : // ============================================================================
     374             : // [asmjit::RAPass - Liveness Analysis]
     375             : // ============================================================================
     376             : 
     377             : //! \internal
     378             : struct LivenessTarget {
     379             :   LivenessTarget* prev;  //!< Previous target.
     380             :   CBLabel* node;         //!< Target node.
     381             :   CBJump* from;          //!< Jumped from.
     382             : };
     383             : 
     384       32111 : Error RAPass::livenessAnalysis() {
     385             :   uint32_t bLen = static_cast<uint32_t>(
     386       32111 :     ((_contextVd.getLength() + RABits::kEntityBits - 1) / RABits::kEntityBits));
     387             : 
     388             :   // No variables.
     389       32111 :   if (bLen == 0)
     390             :     return kErrorOk;
     391             : 
     392             :   CCFunc* func = getFunc();
     393             :   CBJump* from = nullptr;
     394             : 
     395             :   LivenessTarget* ltCur = nullptr;
     396             :   LivenessTarget* ltUnused = nullptr;
     397             : 
     398             :   ZoneList<CBNode*>::Link* retPtr = _returningList.getFirst();
     399             :   ASMJIT_ASSERT(retPtr != nullptr);
     400             : 
     401             :   CBNode* node = retPtr->getValue();
     402             :   RAData* wd;
     403             : 
     404       32111 :   size_t varMapToVaListOffset = _varMapToVaListOffset;
     405             :   RABits* bCur = newBits(bLen);
     406       32111 :   if (ASMJIT_UNLIKELY(!bCur)) goto NoMem;
     407             : 
     408             :   // Allocate bits for code visited first time.
     409      493927 : Visit:
     410             :   for (;;) {
     411             :     wd = node->getPassData<RAData>();
     412      493927 :     if (wd->liveness) {
     413           0 :       if (bCur->_addBitsDelSource(wd->liveness, bCur, bLen))
     414           0 :         goto Patch;
     415             :       else
     416           0 :         goto Done;
     417             :     }
     418             : 
     419             :     RABits* bTmp = copyBits(bCur, bLen);
     420      493927 :     if (!bTmp) goto NoMem;
     421             : 
     422             :     wd = node->getPassData<RAData>();
     423      493927 :     wd->liveness = bTmp;
     424             : 
     425      493927 :     uint32_t tiedTotal = wd->tiedTotal;
     426             :     TiedReg* tiedArray = reinterpret_cast<TiedReg*>(((uint8_t*)wd) + varMapToVaListOffset);
     427             : 
     428     1287504 :     for (uint32_t i = 0; i < tiedTotal; i++) {
     429      793577 :       TiedReg* tied = &tiedArray[i];
     430      793577 :       VirtReg* vreg = tied->vreg;
     431             : 
     432      793577 :       uint32_t flags = tied->flags;
     433      793577 :       uint32_t raId = vreg->_raId;
     434             : 
     435      793577 :       if ((flags & TiedReg::kWAll) && !(flags & TiedReg::kRAll)) {
     436             :         // Write-Only.
     437             :         bTmp->setBit(raId);
     438             :         bCur->delBit(raId);
     439             :       }
     440             :       else {
     441             :         // Read-Only or Read/Write.
     442             :         bTmp->setBit(raId);
     443             :         bCur->setBit(raId);
     444             :       }
     445             :     }
     446             : 
     447      493927 :     if (node->getType() == CBNode::kNodeLabel)
     448           0 :       goto Target;
     449             : 
     450      493927 :     if (node == func)
     451       32111 :       goto Done;
     452             : 
     453             :     ASMJIT_ASSERT(node->getPrev());
     454             :     node = node->getPrev();
     455      461816 :   }
     456             : 
     457             :   // Patch already generated liveness bits.
     458           0 : Patch:
     459             :   for (;;) {
     460             :     ASMJIT_ASSERT(node->hasPassData());
     461             :     ASMJIT_ASSERT(node->getPassData<RAData>()->liveness != nullptr);
     462             : 
     463           0 :     RABits* bNode = node->getPassData<RAData>()->liveness;
     464           0 :     if (!bNode->_addBitsDelSource(bCur, bLen)) goto Done;
     465           0 :     if (node->getType() == CBNode::kNodeLabel) goto Target;
     466             : 
     467           0 :     if (node == func) goto Done;
     468             :     node = node->getPrev();
     469           0 :   }
     470             : 
     471           0 : Target:
     472           0 :   if (static_cast<CBLabel*>(node)->getNumRefs() != 0) {
     473             :     // Push a new LivenessTarget onto the stack if needed.
     474           0 :     if (!ltCur || ltCur->node != node) {
     475             :       // Allocate a new LivenessTarget object (from pool or zone).
     476             :       LivenessTarget* ltTmp = ltUnused;
     477             : 
     478           0 :       if (ltTmp) {
     479           0 :         ltUnused = ltUnused->prev;
     480             :       }
     481             :       else {
     482           0 :         ltTmp = _zone->allocT<LivenessTarget>(
     483           0 :           sizeof(LivenessTarget) - sizeof(RABits) + bLen * sizeof(uintptr_t));
     484           0 :         if (!ltTmp) goto NoMem;
     485             :       }
     486             : 
     487             :       // Initialize and make current - ltTmp->from will be set later on.
     488           0 :       ltTmp->prev = ltCur;
     489           0 :       ltTmp->node = static_cast<CBLabel*>(node);
     490             :       ltCur = ltTmp;
     491             : 
     492             :       from = static_cast<CBLabel*>(node)->getFrom();
     493             :       ASMJIT_ASSERT(from != nullptr);
     494           0 :     }
     495             :     else {
     496           0 :       from = ltCur->from;
     497           0 :       goto JumpNext;
     498             :     }
     499             : 
     500             :     // Visit/Patch.
     501             :     do {
     502           0 :       ltCur->from = from;
     503           0 :       bCur->copyBits(node->getPassData<RAData>()->liveness, bLen);
     504             : 
     505           0 :       if (!from->getPassData<RAData>()->liveness) {
     506             :         node = from;
     507           0 :         goto Visit;
     508             :       }
     509             : 
     510             :       // Issue #25: Moved 'JumpNext' here since it's important to patch
     511             :       // code again if there are more live variables than before.
     512           0 : JumpNext:
     513           0 :       if (bCur->delBits(from->getPassData<RAData>()->liveness, bLen)) {
     514             :         node = from;
     515           0 :         goto Patch;
     516             :       }
     517             : 
     518             :       from = from->getJumpNext();
     519           0 :     } while (from);
     520             : 
     521             :     // Pop the current LivenessTarget from the stack.
     522             :     {
     523             :       LivenessTarget* ltTmp = ltCur;
     524           0 :       ltCur = ltCur->prev;
     525           0 :       ltTmp->prev = ltUnused;
     526             :       ltUnused = ltTmp;
     527             :     }
     528             :   }
     529             : 
     530           0 :   bCur->copyBits(node->getPassData<RAData>()->liveness, bLen);
     531             :   node = node->getPrev();
     532           0 :   if (node->isJmp() || !node->hasPassData()) goto Done;
     533             : 
     534             :   wd = node->getPassData<RAData>();
     535           0 :   if (!wd->liveness) goto Visit;
     536           0 :   if (bCur->delBits(wd->liveness, bLen)) goto Patch;
     537             : 
     538           0 : Done:
     539       32111 :   if (ltCur) {
     540           0 :     node = ltCur->node;
     541           0 :     from = ltCur->from;
     542             : 
     543           0 :     goto JumpNext;
     544             :   }
     545             : 
     546             :   retPtr = retPtr->getNext();
     547       32111 :   if (retPtr) {
     548             :     node = retPtr->getValue();
     549           0 :     goto Visit;
     550             :   }
     551             : 
     552             :   return kErrorOk;
     553             : 
     554             : NoMem:
     555             :   return DebugUtils::errored(kErrorNoHeapMemory);
     556             : }
     557             : 
     558             : // ============================================================================
     559             : // [asmjit::RAPass - Annotate]
     560             : // ============================================================================
     561             : 
     562           0 : Error RAPass::formatInlineComment(StringBuilder& dst, CBNode* node) {
     563             : #if !defined(ASMJIT_DISABLE_LOGGING)
     564             :   RAData* wd = node->getPassData<RAData>();
     565             : 
     566           0 :   if (node->hasInlineComment())
     567             :     dst.appendString(node->getInlineComment());
     568             : 
     569           0 :   if (wd && wd->liveness) {
     570           0 :     if (dst.getLength() < _annotationLength)
     571           0 :       dst.appendChars(' ', _annotationLength - dst.getLength());
     572             : 
     573           0 :     uint32_t vdCount = static_cast<uint32_t>(_contextVd.getLength());
     574           0 :     size_t offset = dst.getLength() + 1;
     575             : 
     576             :     dst.appendChar('[');
     577             :     dst.appendChars(' ', vdCount);
     578             :     dst.appendChar(']');
     579           0 :     RABits* liveness = wd->liveness;
     580             : 
     581             :     uint32_t i;
     582           0 :     for (i = 0; i < vdCount; i++) {
     583           0 :       if (liveness->getBit(i))
     584           0 :         dst.getData()[offset + i] = '.';
     585             :     }
     586             : 
     587           0 :     uint32_t tiedTotal = wd->tiedTotal;
     588           0 :     TiedReg* tiedArray = reinterpret_cast<TiedReg*>(((uint8_t*)wd) + _varMapToVaListOffset);
     589             : 
     590           0 :     for (i = 0; i < tiedTotal; i++) {
     591           0 :       TiedReg* tied = &tiedArray[i];
     592           0 :       VirtReg* vreg = tied->vreg;
     593           0 :       uint32_t flags = tied->flags;
     594             : 
     595             :       char c = 'u';
     596           0 :       if ( (flags & TiedReg::kRAll) && !(flags & TiedReg::kWAll)) c = 'r';
     597           0 :       if (!(flags & TiedReg::kRAll) &&  (flags & TiedReg::kWAll)) c = 'w';
     598           0 :       if ( (flags & TiedReg::kRAll) &&  (flags & TiedReg::kWAll)) c = 'x';
     599             :       // Uppercase if unused.
     600           0 :       if ( (flags & TiedReg::kUnuse)) c -= 'a' - 'A';
     601             : 
     602             :       ASMJIT_ASSERT(offset + vreg->_raId < dst.getLength());
     603           0 :       dst._data[offset + vreg->_raId] = c;
     604             :     }
     605             :   }
     606             : #endif // !ASMJIT_DISABLE_LOGGING
     607             : 
     608           0 :   return kErrorOk;
     609             : }
     610             : 
     611             : } // asmjit namespace
     612             : } // namespace PLMD
     613             : 
     614             : // [Api-End]
     615             : #include "./asmjit_apiend.h"
     616             : 
     617             : // [Guard]
     618             : #endif // !ASMJIT_DISABLE_COMPILER
     619             : #pragma GCC diagnostic pop
     620             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16