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