Home | History | Annotate | Line # | Download | only in Support
      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
    144