xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/OptimizedStructLayout.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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