15ffd83dbSDimitry Andric //===-- OptimizedStructLayout.h - Struct layout algorithm ---------*- C++ -*-=// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric /// 9*fe6060f1SDimitry Andric /// \file 105ffd83dbSDimitry Andric /// This file provides an interface for laying out a sequence of fields 115ffd83dbSDimitry Andric /// as a struct in a way that attempts to minimizes the total space 125ffd83dbSDimitry Andric /// requirements of the struct while still satisfying the layout 135ffd83dbSDimitry Andric /// requirements of the individual fields. The resulting layout may be 145ffd83dbSDimitry Andric /// substantially more compact than simply laying out the fields in their 155ffd83dbSDimitry Andric /// original order. 165ffd83dbSDimitry Andric /// 175ffd83dbSDimitry Andric /// Fields may be pre-assigned fixed offsets. They may also be given sizes 185ffd83dbSDimitry Andric /// that are not multiples of their alignments. There is no currently no 195ffd83dbSDimitry Andric /// way to describe that a field has interior padding that other fields may 205ffd83dbSDimitry Andric /// be allocated into. 215ffd83dbSDimitry Andric /// 225ffd83dbSDimitry Andric /// This algorithm does not claim to be "optimal" for several reasons: 235ffd83dbSDimitry Andric /// 245ffd83dbSDimitry Andric /// - First, it does not guarantee that the result is minimal in size. 255ffd83dbSDimitry Andric /// There is no known efficient algoorithm to achieve minimality for 265ffd83dbSDimitry Andric /// unrestricted inputs. Nonetheless, this algorithm 275ffd83dbSDimitry Andric /// 285ffd83dbSDimitry Andric /// - Second, there are other ways that a struct layout could be optimized 295ffd83dbSDimitry Andric /// besides space usage, such as locality. This layout may have a mixed 305ffd83dbSDimitry Andric /// impact on locality: less overall memory may be used, but adjacent 315ffd83dbSDimitry Andric /// fields in the original array may be moved further from one another. 325ffd83dbSDimitry Andric /// 335ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric #ifndef LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H 365ffd83dbSDimitry Andric #define LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h" 395ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 405ffd83dbSDimitry Andric #include <utility> 415ffd83dbSDimitry Andric 425ffd83dbSDimitry Andric namespace llvm { 435ffd83dbSDimitry Andric 445ffd83dbSDimitry Andric /// A field in a structure. 455ffd83dbSDimitry Andric struct OptimizedStructLayoutField { 465ffd83dbSDimitry Andric /// A special value for Offset indicating that the field can be moved 475ffd83dbSDimitry Andric /// anywhere. 485ffd83dbSDimitry Andric static constexpr uint64_t FlexibleOffset = ~(uint64_t)0; 495ffd83dbSDimitry Andric 505ffd83dbSDimitry Andric OptimizedStructLayoutField(const void *Id, uint64_t Size, Align Alignment, 515ffd83dbSDimitry Andric uint64_t FixedOffset = FlexibleOffset) OffsetOptimizedStructLayoutField525ffd83dbSDimitry Andric : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) { 535ffd83dbSDimitry Andric assert(Size > 0 && "adding an empty field to the layout"); 545ffd83dbSDimitry Andric } 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric /// The offset of this field in the final layout. If this is 575ffd83dbSDimitry Andric /// initialized to FlexibleOffset, layout will overwrite it with 585ffd83dbSDimitry Andric /// the assigned offset of the field. 595ffd83dbSDimitry Andric uint64_t Offset; 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric /// The required size of this field in bytes. Does not have to be 625ffd83dbSDimitry Andric /// a multiple of Alignment. Must be non-zero. 635ffd83dbSDimitry Andric uint64_t Size; 645ffd83dbSDimitry Andric 655ffd83dbSDimitry Andric /// A opaque value which uniquely identifies this field. 665ffd83dbSDimitry Andric const void *Id; 675ffd83dbSDimitry Andric 685ffd83dbSDimitry Andric /// Private scratch space for the algorithm. The implementation 695ffd83dbSDimitry Andric /// must treat this as uninitialized memory on entry. 705ffd83dbSDimitry Andric void *Scratch; 715ffd83dbSDimitry Andric 725ffd83dbSDimitry Andric /// The required alignment of this field. 735ffd83dbSDimitry Andric Align Alignment; 745ffd83dbSDimitry Andric 755ffd83dbSDimitry Andric /// Return true if this field has been assigned a fixed offset. 765ffd83dbSDimitry Andric /// After layout, this will be true of all the fields. hasFixedOffsetOptimizedStructLayoutField775ffd83dbSDimitry Andric bool hasFixedOffset() const { 785ffd83dbSDimitry Andric return (Offset != FlexibleOffset); 795ffd83dbSDimitry Andric } 805ffd83dbSDimitry Andric 815ffd83dbSDimitry Andric /// Given that this field has a fixed offset, return the offset 825ffd83dbSDimitry Andric /// of the first byte following it. getEndOffsetOptimizedStructLayoutField835ffd83dbSDimitry Andric uint64_t getEndOffset() const { 845ffd83dbSDimitry Andric assert(hasFixedOffset()); 855ffd83dbSDimitry Andric return Offset + Size; 865ffd83dbSDimitry Andric } 875ffd83dbSDimitry Andric }; 885ffd83dbSDimitry Andric 895ffd83dbSDimitry Andric /// Compute a layout for a struct containing the given fields, making a 905ffd83dbSDimitry Andric /// best-effort attempt to minimize the amount of space required. 915ffd83dbSDimitry Andric /// 925ffd83dbSDimitry Andric /// Two features are supported which require a more careful solution 935ffd83dbSDimitry Andric /// than the well-known "sort by decreasing alignment" solution: 945ffd83dbSDimitry Andric /// 955ffd83dbSDimitry Andric /// - Fields may be assigned a fixed offset in the layout. If there are 965ffd83dbSDimitry Andric /// gaps among the fixed-offset fields, the algorithm may attempt 975ffd83dbSDimitry Andric /// to allocate flexible-offset fields into those gaps. If that's 985ffd83dbSDimitry Andric /// undesirable, the caller should "block out" those gaps by e.g. 995ffd83dbSDimitry Andric /// just creating a single fixed-offset field that represents the 1005ffd83dbSDimitry Andric /// entire "header". 1015ffd83dbSDimitry Andric /// 1025ffd83dbSDimitry Andric /// - The size of a field is not required to be a multiple of, or even 1035ffd83dbSDimitry Andric /// greater than, the field's required alignment. The only constraint 1045ffd83dbSDimitry Andric /// on fields is that they must not be zero-sized. 1055ffd83dbSDimitry Andric /// 1065ffd83dbSDimitry Andric /// To simplify the implementation, any fixed-offset fields in the 1075ffd83dbSDimitry Andric /// layout must appear at the start of the field array, and they must 1085ffd83dbSDimitry Andric /// be ordered by increasing offset. 1095ffd83dbSDimitry Andric /// 1105ffd83dbSDimitry Andric /// The algorithm will produce a guaranteed-minimal layout with no 1115ffd83dbSDimitry Andric /// interior padding in the following "C-style" case: 1125ffd83dbSDimitry Andric /// 1135ffd83dbSDimitry Andric /// - every field's size is a multiple of its required alignment and 1145ffd83dbSDimitry Andric /// - either no fields have initially fixed offsets, or the fixed-offset 1155ffd83dbSDimitry Andric /// fields have no interior padding and end at an offset that is at 1165ffd83dbSDimitry Andric /// least as aligned as all the flexible-offset fields. 1175ffd83dbSDimitry Andric /// 1185ffd83dbSDimitry Andric /// Otherwise, while the algorithm will make a best-effort attempt to 1195ffd83dbSDimitry Andric /// avoid padding, it cannot guarantee a minimal layout, as there is 1205ffd83dbSDimitry Andric /// no known efficient algorithm for doing so. 1215ffd83dbSDimitry Andric /// 1225ffd83dbSDimitry Andric /// The layout produced by this algorithm may not be stable across LLVM 1235ffd83dbSDimitry Andric /// releases. Do not use this anywhere where ABI stability is required. 1245ffd83dbSDimitry Andric /// 1255ffd83dbSDimitry Andric /// Flexible-offset fields with the same size and alignment will be ordered 1265ffd83dbSDimitry Andric /// the same way they were in the initial array. Otherwise the current 1275ffd83dbSDimitry Andric /// algorithm makes no effort to preserve the initial order of 1285ffd83dbSDimitry Andric /// flexible-offset fields. 1295ffd83dbSDimitry Andric /// 1305ffd83dbSDimitry Andric /// On return, all fields will have been assigned a fixed offset, and the 1315ffd83dbSDimitry Andric /// array will be sorted in order of ascending offsets. Note that this 1325ffd83dbSDimitry Andric /// means that the fixed-offset fields may no longer form a strict prefix 1335ffd83dbSDimitry Andric /// if there's any padding before they end. 1345ffd83dbSDimitry Andric /// 1355ffd83dbSDimitry Andric /// The return value is the total size of the struct and its required 1365ffd83dbSDimitry Andric /// alignment. Note that the total size is not rounded up to a multiple 1375ffd83dbSDimitry Andric /// of the required alignment; clients which require this can do so easily. 1385ffd83dbSDimitry Andric std::pair<uint64_t, Align> performOptimizedStructLayout( 1395ffd83dbSDimitry Andric MutableArrayRef<OptimizedStructLayoutField> Fields); 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric } // namespace llvm 1425ffd83dbSDimitry Andric 1435ffd83dbSDimitry Andric #endif 144