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