OptimizedStructLayout.h 6.1 KB

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