24 Align ComputedMaxAlign;
25 for (
auto &
Field : Fields) {
27 "didn't assign a fixed offset to field");
29 "didn't assign a correctly-aligned offset to field");
31 "didn't assign offsets in ascending order");
34 "didn't compute MaxAlign correctly");
37 assert(LastEnd ==
Size &&
"didn't compute LastEnd correctly");
38 assert(ComputedMaxAlign == MaxAlign &&
"didn't compute MaxAlign correctly");
42std::pair<uint64_t, Align>
47 bool InFixedPrefix =
true;
49 for (
auto &
Field : Fields) {
53 "fixed-offset fields are not a strict prefix of array");
55 "fixed-offset fields overlap or are not in order");
58 "overflow in fixed-offset end offset");
60 InFixedPrefix =
false;
70 auto FirstFlexible = Fields.
begin(), E = Fields.
end();
71 while (FirstFlexible != E && FirstFlexible->hasFixedOffset()) {
72 MaxAlign = std::max(MaxAlign, FirstFlexible->Alignment);
77 if (FirstFlexible == E) {
85 return std::make_pair(
Size, MaxAlign);
94 uintptr_t UniqueNumber = 0;
95 for (
auto I = FirstFlexible;
I != E; ++
I) {
96 I->Scratch =
reinterpret_cast<void*
>(UniqueNumber++);
97 MaxAlign = std::max(MaxAlign,
I->Alignment);
107 [](
const Field *lhs,
const Field *rhs) ->
int {
114 return (lhs->
Size < rhs->
Size ? 1 : -1);
117 auto lhsNumber =
reinterpret_cast<uintptr_t
>(lhs->
Scratch);
118 auto rhsNumber =
reinterpret_cast<uintptr_t
>(rhs->
Scratch);
119 if (lhsNumber != rhsNumber)
120 return (lhsNumber < rhsNumber ? -1 : 1);
132 bool HasPadding =
false;
136 for (
auto I = Fields.
begin();
I != FirstFlexible; ++
I) {
138 if (LastEnd !=
I->Offset) {
142 LastEnd =
I->getEndOffset();
151 for (
auto I = FirstFlexible;
I != E; ++
I) {
158 LastEnd =
I->getEndOffset();
167 return std::make_pair(LastEnd, MaxAlign);
236 struct AlignmentQueue {
255 for (
auto I = FirstFlexible;
I != E; ) {
257 auto Alignment =
I->Alignment;
260 auto LastInQueue =
I;
261 for (++
I;
I != E &&
I->Alignment == Alignment; ++
I) {
262 LastInQueue->Scratch =
I;
264 MinSize = std::min(MinSize,
I->Size);
266 LastInQueue->Scratch =
nullptr;
268 FlexibleFieldsByAlignment.
push_back({MinSize, Head, Alignment});
273 auto checkQueues = [&]{
274 bool FirstQueue =
true;
275 Align LastQueueAlignment;
276 for (
auto &Queue : FlexibleFieldsByAlignment) {
277 assert((FirstQueue || Queue.Alignment < LastQueueAlignment) &&
278 "bins not in order of descending alignment");
279 LastQueueAlignment = Queue.Alignment;
282 assert(Queue.Head &&
"queue was empty");
284 for (
auto I = Queue.Head;
I;
I = Queue.getNext(
I)) {
285 assert(
I->Alignment == Queue.Alignment &&
"bad field in queue");
286 assert(
I->Size <= LastSize &&
"queue not in descending size order");
295 auto spliceFromQueue = [&](AlignmentQueue *Queue,
Field *
Last,
Field *Cur) {
301 Last->Scratch = Cur->Scratch;
307 Queue->MinSize =
Last->Size;
311 if (
auto NewHead = Queue->getNext(Cur))
312 Queue->Head = NewHead;
316 FlexibleFieldsByAlignment.
erase(Queue);
330 auto addToLayout = [&](AlignmentQueue *Queue,
Field *
Last,
Field *Cur,
335 spliceFromQueue(Queue,
Last, Cur);
340 LastEnd = Layout.
back().getEndOffset();
349 auto tryAddFillerFromQueue = [&](AlignmentQueue *Queue,
uint64_t StartOffset,
350 std::optional<uint64_t> EndOffset) ->
bool {
353 assert(!EndOffset || StartOffset < *EndOffset);
358 (EndOffset ? *EndOffset - StartOffset : ~(
uint64_t)0);
359 if (Queue->MinSize > MaxViableSize)
364 for (
Field *Cur = Queue->Head, *
Last =
nullptr;
true;
365 Last = Cur, Cur = Queue->getNext(Cur)) {
366 assert(Cur &&
"didn't find a match in queue despite its MinSize");
367 if (Cur->Size <= MaxViableSize)
368 return addToLayout(Queue,
Last, Cur, StartOffset);
376 auto tryAddBestField = [&](std::optional<uint64_t> BeforeOffset) ->
bool {
377 assert(!BeforeOffset || LastEnd < *BeforeOffset);
378 auto QueueB = FlexibleFieldsByAlignment.
begin();
379 auto QueueE = FlexibleFieldsByAlignment.
end();
383 auto FirstQueueToSearch = QueueB;
384 for (; FirstQueueToSearch != QueueE; ++FirstQueueToSearch) {
385 if (
isAligned(FirstQueueToSearch->Alignment, LastEnd))
396 for (
auto Queue = FirstQueueToSearch; Queue != QueueE; ++Queue) {
397 if (tryAddFillerFromQueue(Queue,
Offset, BeforeOffset))
402 QueueE = FirstQueueToSearch;
405 if (FirstQueueToSearch == QueueB)
411 --FirstQueueToSearch;
413 if (BeforeOffset &&
Offset >= *BeforeOffset)
415 while (FirstQueueToSearch != QueueB &&
416 Offset ==
alignTo(LastEnd, FirstQueueToSearch[-1].Alignment))
417 --FirstQueueToSearch;
423 for (
auto I = Fields.
begin();
I != FirstFlexible; ++
I) {
425 while (LastEnd !=
I->Offset) {
426 if (!tryAddBestField(
I->Offset))
430 LastEnd =
I->getEndOffset();
439 while (!FlexibleFieldsByAlignment.
empty()) {
440 bool Success = tryAddBestField(std::nullopt);
441 assert(
Success &&
"didn't find a field with no fixed limit?");
447 memcpy(Fields.
data(), Layout.
data(),
455 return std::make_pair(LastEnd, MaxAlign);
static void checkValidLayout(ArrayRef< Field > Fields, uint64_t Size, Align MaxAlign)
This file provides an interface for laying out a sequence of fields as a struct in a way that attempt...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
T & back() const
back - Get the last element.
void reserve(size_type N)
iterator erase(const_iterator CI)
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
std::pair< uint64_t, Align > performOptimizedStructLayout(MutableArrayRef< OptimizedStructLayoutField > Fields)
Compute a layout for a struct containing the given fields, making a best-effort attempt to minimize t...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Align Alignment
The required alignment of this field.
uint64_t getEndOffset() const
Given that this field has a fixed offset, return the offset of the first byte following it.
void * Scratch
Private scratch space for the algorithm.
bool hasFixedOffset() const
Return true if this field has been assigned a fixed offset.
uint64_t Offset
The offset of this field in the final layout.
uint64_t Size
The required size of this field in bytes.