blob: 773ddfeaf13a99c381e374bbaf8ec88026eeb39e [file] [log] [blame]
Olivier Deprezf4ef2d02021-04-20 13:36:24 +02001//===-- OptimizedStructLayout.h - Struct layout algorithm ---------*- C++ -*-=//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// This file provides an interface for laying out a sequence of fields
10/// as a struct in a way that attempts to minimizes the total space
11/// requirements of the struct while still satisfying the layout
12/// requirements of the individual fields. The resulting layout may be
13/// substantially more compact than simply laying out the fields in their
14/// original order.
15///
16/// Fields may be pre-assigned fixed offsets. They may also be given sizes
17/// that are not multiples of their alignments. There is no currently no
18/// way to describe that a field has interior padding that other fields may
19/// be allocated into.
20///
21/// This algorithm does not claim to be "optimal" for several reasons:
22///
23/// - First, it does not guarantee that the result is minimal in size.
24/// There is no known efficient algoorithm to achieve minimality for
25/// unrestricted inputs. Nonetheless, this algorithm
26///
27/// - Second, there are other ways that a struct layout could be optimized
28/// besides space usage, such as locality. This layout may have a mixed
29/// impact on locality: less overall memory may be used, but adjacent
30/// fields in the original array may be moved further from one another.
31///
32//===----------------------------------------------------------------------===//
33
34#ifndef LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
35#define LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
36
37#include "llvm/Support/Alignment.h"
38#include "llvm/ADT/ArrayRef.h"
39#include <utility>
40
41namespace llvm {
42
43/// A field in a structure.
44struct OptimizedStructLayoutField {
45 /// A special value for Offset indicating that the field can be moved
46 /// anywhere.
47 static constexpr uint64_t FlexibleOffset = ~(uint64_t)0;
48
49 OptimizedStructLayoutField(const void *Id, uint64_t Size, Align Alignment,
50 uint64_t FixedOffset = FlexibleOffset)
51 : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) {
52 assert(Size > 0 && "adding an empty field to the layout");
53 }
54
55 /// The offset of this field in the final layout. If this is
56 /// initialized to FlexibleOffset, layout will overwrite it with
57 /// the assigned offset of the field.
58 uint64_t Offset;
59
60 /// The required size of this field in bytes. Does not have to be
61 /// a multiple of Alignment. Must be non-zero.
62 uint64_t Size;
63
64 /// A opaque value which uniquely identifies this field.
65 const void *Id;
66
67 /// Private scratch space for the algorithm. The implementation
68 /// must treat this as uninitialized memory on entry.
69 void *Scratch;
70
71 /// The required alignment of this field.
72 Align Alignment;
73
74 /// Return true if this field has been assigned a fixed offset.
75 /// After layout, this will be true of all the fields.
76 bool hasFixedOffset() const {
77 return (Offset != FlexibleOffset);
78 }
79
80 /// Given that this field has a fixed offset, return the offset
81 /// of the first byte following it.
82 uint64_t getEndOffset() const {
83 assert(hasFixedOffset());
84 return Offset + Size;
85 }
86};
87
88/// Compute a layout for a struct containing the given fields, making a
89/// best-effort attempt to minimize the amount of space required.
90///
91/// Two features are supported which require a more careful solution
92/// than the well-known "sort by decreasing alignment" solution:
93///
94/// - Fields may be assigned a fixed offset in the layout. If there are
95/// gaps among the fixed-offset fields, the algorithm may attempt
96/// to allocate flexible-offset fields into those gaps. If that's
97/// undesirable, the caller should "block out" those gaps by e.g.
98/// just creating a single fixed-offset field that represents the
99/// entire "header".
100///
101/// - The size of a field is not required to be a multiple of, or even
102/// greater than, the field's required alignment. The only constraint
103/// on fields is that they must not be zero-sized.
104///
105/// To simplify the implementation, any fixed-offset fields in the
106/// layout must appear at the start of the field array, and they must
107/// be ordered by increasing offset.
108///
109/// The algorithm will produce a guaranteed-minimal layout with no
110/// interior padding in the following "C-style" case:
111///
112/// - every field's size is a multiple of its required alignment and
113/// - either no fields have initially fixed offsets, or the fixed-offset
114/// fields have no interior padding and end at an offset that is at
115/// least as aligned as all the flexible-offset fields.
116///
117/// Otherwise, while the algorithm will make a best-effort attempt to
118/// avoid padding, it cannot guarantee a minimal layout, as there is
119/// no known efficient algorithm for doing so.
120///
121/// The layout produced by this algorithm may not be stable across LLVM
122/// releases. Do not use this anywhere where ABI stability is required.
123///
124/// Flexible-offset fields with the same size and alignment will be ordered
125/// the same way they were in the initial array. Otherwise the current
126/// algorithm makes no effort to preserve the initial order of
127/// flexible-offset fields.
128///
129/// On return, all fields will have been assigned a fixed offset, and the
130/// array will be sorted in order of ascending offsets. Note that this
131/// means that the fixed-offset fields may no longer form a strict prefix
132/// if there's any padding before they end.
133///
134/// The return value is the total size of the struct and its required
135/// alignment. Note that the total size is not rounded up to a multiple
136/// of the required alignment; clients which require this can do so easily.
137std::pair<uint64_t, Align> performOptimizedStructLayout(
138 MutableArrayRef<OptimizedStructLayoutField> Fields);
139
140} // namespace llvm
141
142#endif