LLVM  14.0.0git
TrailingObjects.h
Go to the documentation of this file.
1 //===--- TrailingObjects.h - Variable-length classes ------------*- 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 header defines support for implementing classes that have
11 /// some trailing object (or arrays of objects) appended to them. The
12 /// main purpose is to make it obvious where this idiom is being used,
13 /// and to make the usage more idiomatic and more difficult to get
14 /// wrong.
15 ///
16 /// The TrailingObject template abstracts away the reinterpret_cast,
17 /// pointer arithmetic, and size calculations used for the allocation
18 /// and access of appended arrays of objects, and takes care that they
19 /// are all allocated at their required alignment. Additionally, it
20 /// ensures that the base type is final -- deriving from a class that
21 /// expects data appended immediately after it is typically not safe.
22 ///
23 /// Users are expected to derive from this template, and provide
24 /// numTrailingObjects implementations for each trailing type except
25 /// the last, e.g. like this sample:
26 ///
27 /// \code
28 /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
29 /// friend TrailingObjects;
30 ///
31 /// unsigned NumInts, NumDoubles;
32 /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
33 /// };
34 /// \endcode
35 ///
36 /// You can access the appended arrays via 'getTrailingObjects', and
37 /// determine the size needed for allocation via
38 /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
39 ///
40 /// All the methods implemented by this class are are intended for use
41 /// by the implementation of the class, not as part of its interface
42 /// (thus, private inheritance is suggested).
43 ///
44 //===----------------------------------------------------------------------===//
45 
46 #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
47 #define LLVM_SUPPORT_TRAILINGOBJECTS_H
48 
49 #include "llvm/Support/AlignOf.h"
50 #include "llvm/Support/Alignment.h"
51 #include "llvm/Support/Compiler.h"
54 #include <new>
55 #include <type_traits>
56 
57 namespace llvm {
58 
59 namespace trailing_objects_internal {
60 /// Helper template to calculate the max alignment requirement for a set of
61 /// objects.
62 template <typename First, typename... Rest> class AlignmentCalcHelper {
63 private:
64  enum {
65  FirstAlignment = alignof(First),
67  };
68 
69 public:
70  enum {
71  Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
72  };
73 };
74 
75 template <typename First> class AlignmentCalcHelper<First> {
76 public:
77  enum { Alignment = alignof(First) };
78 };
79 
80 /// The base class for TrailingObjects* classes.
82 protected:
83  /// OverloadToken's purpose is to allow specifying function overloads
84  /// for different types, without actually taking the types as
85  /// parameters. (Necessary because member function templates cannot
86  /// be specialized, so overloads must be used instead of
87  /// specialization.)
88  template <typename T> struct OverloadToken {};
89 };
90 
91 // Just a little helper for transforming a type pack into the same
92 // number of a different type. e.g.:
93 // ExtractSecondType<Foo..., int>::type
94 template <typename Ty1, typename Ty2> struct ExtractSecondType {
95  typedef Ty2 type;
96 };
97 
98 // TrailingObjectsImpl is somewhat complicated, because it is a
99 // recursively inheriting template, in order to handle the template
100 // varargs. Each level of inheritance picks off a single trailing type
101 // then recurses on the rest. The "Align", "BaseTy", and
102 // "TopTrailingObj" arguments are passed through unchanged through the
103 // recursion. "PrevTy" is, at each level, the type handled by the
104 // level right above it.
105 
106 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
107  typename... MoreTys>
109  // The main template definition is never used -- the two
110  // specializations cover all possibilities.
111 };
112 
113 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
114  typename NextTy, typename... MoreTys>
115 class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
116  MoreTys...>
117  : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
118  MoreTys...> {
119 
120  typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
121  ParentType;
122 
123  struct RequiresRealignment {
124  static const bool value = alignof(PrevTy) < alignof(NextTy);
125  };
126 
127  static constexpr bool requiresRealignment() {
128  return RequiresRealignment::value;
129  }
130 
131 protected:
132  // Ensure the inherited getTrailingObjectsImpl is not hidden.
133  using ParentType::getTrailingObjectsImpl;
134 
135  // These two functions are helper functions for
136  // TrailingObjects::getTrailingObjects. They recurse to the left --
137  // the result for each type in the list of trailing types depends on
138  // the result of calling the function on the type to the
139  // left. However, the function for the type to the left is
140  // implemented by a *subclass* of this class, so we invoke it via
141  // the TopTrailingObj, which is, via the
142  // curiously-recurring-template-pattern, the most-derived type in
143  // this recursion, and thus, contains all the overloads.
144  static const NextTy *
145  getTrailingObjectsImpl(const BaseTy *Obj,
147  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
149  TopTrailingObj::callNumTrailingObjects(
151 
152  if (requiresRealignment())
153  return reinterpret_cast<const NextTy *>(
154  alignAddr(Ptr, Align::Of<NextTy>()));
155  else
156  return reinterpret_cast<const NextTy *>(Ptr);
157  }
158 
159  static NextTy *
162  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
164  TopTrailingObj::callNumTrailingObjects(
166 
167  if (requiresRealignment())
168  return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
169  else
170  return reinterpret_cast<NextTy *>(Ptr);
171  }
172 
173  // Helper function for TrailingObjects::additionalSizeToAlloc: this
174  // function recurses to superclasses, each of which requires one
175  // fewer size_t argument, and adds its own size.
176  static constexpr size_t additionalSizeToAllocImpl(
177  size_t SizeSoFar, size_t Count1,
178  typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
179  return ParentType::additionalSizeToAllocImpl(
180  (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
181  : SizeSoFar) +
182  sizeof(NextTy) * Count1,
183  MoreCounts...);
184  }
185 };
186 
187 // The base case of the TrailingObjectsImpl inheritance recursion,
188 // when there's no more trailing types.
189 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
190 class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
191  : public TrailingObjectsBase {
192 protected:
193  // This is a dummy method, only here so the "using" doesn't fail --
194  // it will never be called, because this function recurses backwards
195  // up the inheritance chain to subclasses.
196  static void getTrailingObjectsImpl();
197 
198  static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
199  return SizeSoFar;
200  }
201 
202  template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
203 };
204 
205 } // end namespace trailing_objects_internal
206 
207 // Finally, the main type defined in this file, the one intended for users...
208 
209 /// See the file comment for details on the usage of the
210 /// TrailingObjects type.
211 template <typename BaseTy, typename... TrailingTys>
213  trailing_objects_internal::AlignmentCalcHelper<
214  TrailingTys...>::Alignment,
215  BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
216  BaseTy, TrailingTys...> {
217 
218  template <int A, typename B, typename T, typename P, typename... M>
220 
221  template <typename... Tys> class Foo {};
222 
224  trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
225  BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
226  ParentType;
227  using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase;
228 
229  using ParentType::getTrailingObjectsImpl;
230 
231  // This function contains only a static_assert BaseTy is final. The
232  // static_assert must be in a function, and not at class-level
233  // because BaseTy isn't complete at class instantiation time, but
234  // will be by the time this function is instantiated.
235  static void verifyTrailingObjectsAssertions() {
236  static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
237  }
238 
239  // These two methods are the base of the recursion for this method.
240  static const BaseTy *
241  getTrailingObjectsImpl(const BaseTy *Obj,
242  TrailingObjectsBase::OverloadToken<BaseTy>) {
243  return Obj;
244  }
245 
246  static BaseTy *
247  getTrailingObjectsImpl(BaseTy *Obj,
248  TrailingObjectsBase::OverloadToken<BaseTy>) {
249  return Obj;
250  }
251 
252  // callNumTrailingObjects simply calls numTrailingObjects on the
253  // provided Obj -- except when the type being queried is BaseTy
254  // itself. There is always only one of the base object, so that case
255  // is handled here. (An additional benefit of indirecting through
256  // this function is that consumers only say "friend
257  // TrailingObjects", and thus, only this class itself can call the
258  // numTrailingObjects function.)
259  static size_t
260  callNumTrailingObjects(const BaseTy *Obj,
261  TrailingObjectsBase::OverloadToken<BaseTy>) {
262  return 1;
263  }
264 
265  template <typename T>
266  static size_t callNumTrailingObjects(const BaseTy *Obj,
267  TrailingObjectsBase::OverloadToken<T>) {
268  return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
269  }
270 
271 public:
272  // Make this (privately inherited) member public.
273 #ifndef _MSC_VER
274  using ParentType::OverloadToken;
275 #else
276  // An MSVC bug prevents the above from working, (last tested at CL version
277  // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case.
278  template <typename T>
279  using OverloadToken = typename ParentType::template OverloadToken<T>;
280 #endif
281 
282  /// Returns a pointer to the trailing object array of the given type
283  /// (which must be one of those specified in the class template). The
284  /// array may have zero or more elements in it.
285  template <typename T> const T *getTrailingObjects() const {
286  verifyTrailingObjectsAssertions();
287  // Forwards to an impl function with overloads, since member
288  // function templates can't be specialized.
289  return this->getTrailingObjectsImpl(
290  static_cast<const BaseTy *>(this),
292  }
293 
294  /// Returns a pointer to the trailing object array of the given type
295  /// (which must be one of those specified in the class template). The
296  /// array may have zero or more elements in it.
297  template <typename T> T *getTrailingObjects() {
298  verifyTrailingObjectsAssertions();
299  // Forwards to an impl function with overloads, since member
300  // function templates can't be specialized.
301  return this->getTrailingObjectsImpl(
302  static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
303  }
304 
305  /// Returns the size of the trailing data, if an object were
306  /// allocated with the given counts (The counts are in the same order
307  /// as the template arguments). This does not include the size of the
308  /// base object. The template arguments must be the same as those
309  /// used in the class; they are supplied here redundantly only so
310  /// that it's clear what the counts are counting in callers.
311  template <typename... Tys>
312  static constexpr std::enable_if_t<
313  std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
315  TrailingTys, size_t>::type... Counts) {
316  return ParentType::additionalSizeToAllocImpl(0, Counts...);
317  }
318 
319  /// Returns the total size of an object if it were allocated with the
320  /// given trailing object counts. This is the same as
321  /// additionalSizeToAlloc, except it *does* include the size of the base
322  /// object.
323  template <typename... Tys>
324  static constexpr std::enable_if_t<
325  std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
327  TrailingTys, size_t>::type... Counts) {
328  return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
329  }
330 
331  TrailingObjects() = default;
332  TrailingObjects(const TrailingObjects &) = delete;
333  TrailingObjects(TrailingObjects &&) = delete;
334  TrailingObjects &operator=(const TrailingObjects &) = delete;
335  TrailingObjects &operator=(TrailingObjects &&) = delete;
336 
337  /// A type where its ::with_counts template member has a ::type member
338  /// suitable for use as uninitialized storage for an object with the given
339  /// trailing object counts. The template arguments are similar to those
340  /// of additionalSizeToAlloc.
341  ///
342  /// Use with FixedSizeStorageOwner, e.g.:
343  ///
344  /// \code{.cpp}
345  ///
346  /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage;
347  /// MyObj::FixedSizeStorageOwner
348  /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj);
349  /// MyObj *const myStackObjPtr = myStackObjOwner.get();
350  ///
351  /// \endcode
352  template <typename... Tys> struct FixedSizeStorage {
353  template <size_t... Counts> struct with_counts {
354  enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
355  struct type {
356  alignas(BaseTy) char buffer[Size];
357  };
358  };
359  };
360 
361  /// A type that acts as the owner for an object placed into fixed storage.
363  public:
364  FixedSizeStorageOwner(BaseTy *p) : p(p) {}
366  assert(p && "FixedSizeStorageOwner owns null?");
367  p->~BaseTy();
368  }
369 
370  BaseTy *get() { return p; }
371  const BaseTy *get() const { return p; }
372 
373  private:
376  FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
377  FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
378 
379  BaseTy *const p;
380  };
381 };
382 
383 } // end namespace llvm
384 
385 #endif
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:148
llvm::trailing_objects_internal::ExtractSecondType::type
Ty2 type
Definition: TrailingObjects.h:95
MathExtras.h
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
llvm::trailing_objects_internal::TrailingObjectsImpl< Align, BaseTy, TopTrailingObj, PrevTy >::verifyTrailingObjectsAlignment
static void verifyTrailingObjectsAlignment()
Definition: TrailingObjects.h:202
llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken
OverloadToken's purpose is to allow specifying function overloads for different types,...
Definition: TrailingObjects.h:88
llvm::alignAddr
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Definition: Alignment.h:186
llvm::TrailingObjects::totalSizeToAlloc
static constexpr std::enable_if_t< std::is_same< Foo< TrailingTys... >, Foo< Tys... > >::value, size_t > totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t >::type... Counts)
Returns the total size of an object if it were allocated with the given trailing object counts.
Definition: TrailingObjects.h:326
T
#define T
Definition: Mips16ISelLowering.cpp:341
llvm::trailing_objects_internal::TrailingObjectsImpl< Align, BaseTy, TopTrailingObj, PrevTy, NextTy, MoreTys... >::additionalSizeToAllocImpl
static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar, size_t Count1, typename ExtractSecondType< MoreTys, size_t >::type... MoreCounts)
Definition: TrailingObjects.h:176
AlignOf.h
p
the resulting code requires compare and branches when and if * p
Definition: README.txt:396
llvm::trailing_objects_internal::TrailingObjectsImpl< Align, BaseTy, TopTrailingObj, PrevTy, NextTy, MoreTys... >::getTrailingObjectsImpl
static const NextTy * getTrailingObjectsImpl(const BaseTy *Obj, TrailingObjectsBase::OverloadToken< NextTy >)
Definition: TrailingObjects.h:145
size_t
llvm::TrailingObjects::additionalSizeToAlloc
static constexpr std::enable_if_t< std::is_same< Foo< TrailingTys... >, Foo< Tys... > >::value, size_t > additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t >::type... Counts)
Returns the size of the trailing data, if an object were allocated with the given counts (The counts ...
Definition: TrailingObjects.h:314
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
First
into llvm powi allowing the code generator to produce balanced multiplication trees First
Definition: README.txt:54
llvm::trailing_objects_internal::ExtractSecondType
Definition: TrailingObjects.h:94
llvm::TrailingObjects::FixedSizeStorageOwner::FixedSizeStorageOwner
FixedSizeStorageOwner(BaseTy *p)
Definition: TrailingObjects.h:364
llvm::TrailingObjects::FixedSizeStorageOwner::get
const BaseTy * get() const
Definition: TrailingObjects.h:371
Align
uint64_t Align
Definition: ELFObjHandler.cpp:83
llvm::Align
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
type
AMD64 Optimization Manual has some nice information about optimizing integer multiplication by a constant How much of it applies to Intel s X86 implementation There are definite trade offs to xmm0 cvttss2siq rdx jb L3 subss xmm0 rax cvttss2siq rdx xorq rdx rax ret instead of xmm1 cvttss2siq rcx movaps xmm2 subss xmm2 cvttss2siq rax rdx xorq rax ucomiss xmm0 cmovb rax ret Seems like the jb branch has high likelihood of being taken It would have saved a few instructions It s not possible to reference and DH registers in an instruction requiring REX prefix divb and mulb both produce results in AH If isel emits a CopyFromReg which gets turned into a movb and that can be allocated a r8b r15b To get around isel emits a CopyFromReg from AX and then right shift it down by and truncate it It s not pretty but it works We need some register allocation magic to make the hack go which would often require a callee saved register Callees usually need to keep this value live for most of their body so it doesn t add a significant burden on them We currently implement this in however this is suboptimal because it means that it would be quite awkward to implement the optimization for callers A better implementation would be to relax the LLVM IR rules for sret arguments to allow a function with an sret argument to have a non void return type
Definition: README-X86-64.txt:70
llvm::trailing_objects_internal::TrailingObjectsImpl< Align, BaseTy, TopTrailingObj, PrevTy, NextTy, MoreTys... >::getTrailingObjectsImpl
static NextTy * getTrailingObjectsImpl(BaseTy *Obj, TrailingObjectsBase::OverloadToken< NextTy >)
Definition: TrailingObjects.h:160
llvm::trailing_objects_internal::TrailingObjectsImpl< Align, BaseTy, TopTrailingObj, PrevTy >::additionalSizeToAllocImpl
static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar)
Definition: TrailingObjects.h:198
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::TrailingObjects::FixedSizeStorageOwner::get
BaseTy * get()
Definition: TrailingObjects.h:370
llvm::trailing_objects_internal::AlignmentCalcHelper
Helper template to calculate the max alignment requirement for a set of objects.
Definition: TrailingObjects.h:62
llvm::trailing_objects_internal::TrailingObjectsBase
The base class for TrailingObjects* classes.
Definition: TrailingObjects.h:81
llvm::TrailingObjects::getTrailingObjects
const T * getTrailingObjects() const
Returns a pointer to the trailing object array of the given type (which must be one of those specifie...
Definition: TrailingObjects.h:285
llvm::TrailingObjects::FixedSizeStorageOwner
A type that acts as the owner for an object placed into fixed storage.
Definition: TrailingObjects.h:362
Compiler.h
llvm::TrailingObjects::FixedSizeStorage
A type where its ::with_counts template member has a type member suitable for use as uninitialized st...
Definition: TrailingObjects.h:352
Alignment.h
type_traits.h
llvm::TrailingObjects::FixedSizeStorage::with_counts
Definition: TrailingObjects.h:353
llvm::TrailingObjects
See the file comment for details on the usage of the TrailingObjects type.
Definition: TrailingObjects.h:212
llvm::TrailingObjects::FixedSizeStorageOwner::~FixedSizeStorageOwner
~FixedSizeStorageOwner()
Definition: TrailingObjects.h:365
llvm::trailing_objects_internal::TrailingObjectsImpl
Definition: TrailingObjects.h:108
llvm::TrailingObjects::FixedSizeStorage::with_counts::type
Definition: TrailingObjects.h:355
llvm::TrailingObjects::getTrailingObjects
T * getTrailingObjects()
Returns a pointer to the trailing object array of the given type (which must be one of those specifie...
Definition: TrailingObjects.h:297