LCOV - code coverage report
Current view: top level - asmjit - rastack.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 35 56 62.5 %
Date: 2026-11-05 10:19:06 Functions: 2 3 66.7 %

          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 "rastack_p.h"
      11             : #include "support.h"
      12             : 
      13             : ASMJIT_BEGIN_NAMESPACE
      14             : 
      15             : // RAStackAllocator - Slots
      16             : // ========================
      17             : 
      18       30798 : RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32_t alignment, uint32_t flags) noexcept {
      19       30798 :   if (ASMJIT_UNLIKELY(_slots.willGrow(allocator(), 1) != kErrorOk))
      20             :     return nullptr;
      21             : 
      22       30798 :   RAStackSlot* slot = allocator()->allocT<RAStackSlot>();
      23       30798 :   if (ASMJIT_UNLIKELY(!slot))
      24             :     return nullptr;
      25             : 
      26       30798 :   slot->_baseRegId = uint8_t(baseRegId);
      27       30798 :   slot->_alignment = uint8_t(Support::max<uint32_t>(alignment, 1));
      28       30798 :   slot->_flags = uint16_t(flags);
      29       30798 :   slot->_useCount = 0;
      30       30798 :   slot->_size = size;
      31             : 
      32       30798 :   slot->_weight = 0;
      33       30798 :   slot->_offset = 0;
      34             : 
      35       30798 :   _alignment = Support::max<uint32_t>(_alignment, alignment);
      36             :   _slots.appendUnsafe(slot);
      37       30798 :   return slot;
      38             : }
      39             : 
      40             : // RAStackAllocator - Utilities
      41             : // ============================
      42             : 
      43             : struct RAStackGap {
      44             :   inline RAStackGap() noexcept
      45             :     : offset(0),
      46             :       size(0) {}
      47             : 
      48             :   inline RAStackGap(uint32_t offset, uint32_t size) noexcept
      49           0 :     : offset(offset),
      50           0 :       size(size) {}
      51             : 
      52             :   inline RAStackGap(const RAStackGap& other) noexcept
      53           0 :     : offset(other.offset),
      54           0 :       size(other.size) {}
      55             : 
      56             :   uint32_t offset;
      57             :   uint32_t size;
      58             : };
      59             : 
      60       27492 : Error RAStackAllocator::calculateStackFrame() noexcept {
      61             :   // Base weight added to all registers regardless of their size and alignment.
      62             :   uint32_t kBaseRegWeight = 16;
      63             : 
      64             :   // STEP 1:
      65             :   //
      66             :   // Update usage based on the size of the slot. We boost smaller slots in a way that 32-bit register has higher
      67             :   // priority than a 128-bit register, however, if one 128-bit register is used 4 times more than some other 32-bit
      68             :   // register it will overweight it.
      69       58290 :   for (RAStackSlot* slot : _slots) {
      70             :     uint32_t alignment = slot->alignment();
      71             :     ASMJIT_ASSERT(alignment > 0);
      72             : 
      73             :     uint32_t power = Support::min<uint32_t>(Support::ctz(alignment), 6);
      74             :     uint64_t weight;
      75             : 
      76       30798 :     if (slot->isRegHome())
      77       30798 :       weight = kBaseRegWeight + (uint64_t(slot->useCount()) * (7 - power));
      78             :     else
      79           0 :       weight = power;
      80             : 
      81             :     // If overflown, which has less chance of winning a lottery, just use max possible weight. In such case it
      82             :     // probably doesn't matter at all.
      83       30798 :     if (weight > 0xFFFFFFFFu)
      84             :       weight = 0xFFFFFFFFu;
      85             : 
      86       30798 :     slot->setWeight(uint32_t(weight));
      87             :   }
      88             : 
      89             :   // STEP 2:
      90             :   //
      91             :   // Sort stack slots based on their newly calculated weight (in descending order).
      92       27492 :   _slots.sort([](const RAStackSlot* a, const RAStackSlot* b) noexcept {
      93       84519 :     return a->weight() >  b->weight() ? 1 :
      94       29341 :            a->weight() == b->weight() ? 0 : -1;
      95             :   });
      96             : 
      97             :   // STEP 3:
      98             :   //
      99             :   // Calculate offset of each slot. We start from the slot that has the highest weight and advance to slots with
     100             :   // lower weight. It could look that offsets start from the first slot in our list and then simply increase, but
     101             :   // it's not always the case as we also try to fill all gaps introduced by the fact that slots are sorted by
     102             :   // weight and not by size & alignment, so when we need to align some slot we distribute the gap caused by the
     103             :   // alignment to `gaps`.
     104             :   uint32_t offset = 0;
     105      192444 :   ZoneVector<RAStackGap> gaps[kSizeCount - 1];
     106             : 
     107       58290 :   for (RAStackSlot* slot : _slots) {
     108       30798 :     if (slot->isStackArg())
     109           0 :       continue;
     110             : 
     111             :     uint32_t slotAlignment = slot->alignment();
     112             :     uint32_t alignedOffset = Support::alignUp(offset, slotAlignment);
     113             : 
     114             :     // Try to find a slot within gaps first, before advancing the `offset`.
     115             :     bool foundGap = false;
     116             :     uint32_t gapSize = 0;
     117             :     uint32_t gapOffset = 0;
     118             : 
     119             :     {
     120             :       uint32_t slotSize = slot->size();
     121       30798 :       if (slotSize < (1u << uint32_t(ASMJIT_ARRAY_SIZE(gaps)))) {
     122             :         // Iterate from the lowest to the highest possible.
     123             :         uint32_t index = Support::ctz(slotSize);
     124             :         do {
     125       92394 :           if (!gaps[index].empty()) {
     126             :             RAStackGap gap = gaps[index].pop();
     127             : 
     128             :             ASMJIT_ASSERT(Support::isAligned(gap.offset, slotAlignment));
     129           0 :             slot->setOffset(int32_t(gap.offset));
     130             : 
     131           0 :             gapSize = gap.size - slotSize;
     132           0 :             gapOffset = gap.offset - slotSize;
     133             : 
     134             :             foundGap = true;
     135             :             break;
     136             :           }
     137       92394 :         } while (++index < uint32_t(ASMJIT_ARRAY_SIZE(gaps)));
     138             :       }
     139             :     }
     140             : 
     141             :     // No gap found, we may create a new one(s) if the current offset is not aligned.
     142       30798 :     if (!foundGap && offset != alignedOffset) {
     143           0 :       gapSize = alignedOffset - offset;
     144             :       gapOffset = alignedOffset;
     145             : 
     146             :       offset = alignedOffset;
     147             :     }
     148             : 
     149             :     // True if we have found a gap and not filled all of it or we aligned the current offset.
     150       30798 :     if (gapSize) {
     151           0 :       uint32_t gapEnd = gapSize + gapOffset;
     152           0 :       while (gapOffset < gapEnd) {
     153             :         uint32_t index = Support::ctz(gapOffset);
     154           0 :         uint32_t slotSize = 1u << index;
     155             : 
     156             :         // Weird case, better to bail...
     157           0 :         if (gapEnd - gapOffset < slotSize)
     158             :           break;
     159             : 
     160           0 :         ASMJIT_PROPAGATE(gaps[index].append(allocator(), RAStackGap(gapOffset, slotSize)));
     161           0 :         gapOffset += slotSize;
     162             :       }
     163             :     }
     164             : 
     165       30798 :     if (!foundGap) {
     166             :       ASMJIT_ASSERT(Support::isAligned(offset, slotAlignment));
     167       30798 :       slot->setOffset(int32_t(offset));
     168       30798 :       offset += slot->size();
     169             :     }
     170             :   }
     171             : 
     172       27492 :   _stackSize = Support::alignUp(offset, _alignment);
     173       27492 :   return kErrorOk;
     174             : }
     175             : 
     176           0 : Error RAStackAllocator::adjustSlotOffsets(int32_t offset) noexcept {
     177           0 :   for (RAStackSlot* slot : _slots)
     178           0 :     if (!slot->isStackArg())
     179           0 :       slot->_offset += offset;
     180           0 :   return kErrorOk;
     181             : }
     182             : 
     183             : ASMJIT_END_NAMESPACE
     184             : 
     185             : #endif // !ASMJIT_NO_COMPILER
     186             : 
     187             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16