1//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the AlignOf function that computes alignments for
11// arbitrary types.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_SUPPORT_ALIGNOF_H
16#define LLVM_SUPPORT_ALIGNOF_H
17
18#include "llvm/Support/Compiler.h"
19#include <cstddef>
20#include <type_traits>
21
22namespace llvm {
23
24namespace detail {
25
26// For everything other than an abstract class we can calulate alignment by
27// building a class with a single character and a member of the given type.
28template <typename T, bool = std::is_abstract<T>::value>
29struct AlignmentCalcImpl {
30  char x;
31#if defined(_MSC_VER)
32// Disables "structure was padded due to __declspec(align())" warnings that are
33// generated by any class using AlignOf<T> with a manually specified alignment.
34// Although the warning is disabled in the LLVM project we need this pragma
35// as AlignOf.h is a published support header that's available for use
36// out-of-tree, and we would like that to compile cleanly at /W4.
37#pragma warning(suppress : 4324)
38#endif
39  T t;
40private:
41  AlignmentCalcImpl() = delete;
42};
43
44// Abstract base class helper, this will have the minimal alignment and size
45// for any abstract class. We don't even define its destructor because this
46// type should never be used in a way that requires it.
47struct AlignmentCalcImplBase {
48  virtual ~AlignmentCalcImplBase() = 0;
49};
50
51// When we have an abstract class type, specialize the alignment computation
52// engine to create another abstract class that derives from both an empty
53// abstract base class and the provided type. This has the same effect as the
54// above except that it handles the fact that we can't actually create a member
55// of type T.
56template <typename T>
57struct AlignmentCalcImpl<T, true> : AlignmentCalcImplBase, T {
58  ~AlignmentCalcImpl() override = 0;
59};
60
61} // End detail namespace.
62
63/// AlignOf - A templated class that contains an enum value representing
64///  the alignment of the template argument.  For example,
65///  AlignOf<int>::Alignment represents the alignment of type "int".  The
66///  alignment calculated is the minimum alignment, and not necessarily
67///  the "desired" alignment returned by GCC's __alignof__ (for example).  Note
68///  that because the alignment is an enum value, it can be used as a
69///  compile-time constant (e.g., for template instantiation).
70template <typename T>
71struct AlignOf {
72#ifndef _MSC_VER
73  // Avoid warnings from GCC like:
74  //   comparison between 'enum llvm::AlignOf<X>::<anonymous>' and 'enum
75  //   llvm::AlignOf<Y>::<anonymous>' [-Wenum-compare]
76  // by using constexpr instead of enum.
77  // (except on MSVC, since it doesn't support constexpr yet).
78  static constexpr unsigned Alignment = static_cast<unsigned int>(
79      sizeof(detail::AlignmentCalcImpl<T>) - sizeof(T));
80#else
81  enum {
82    Alignment = static_cast<unsigned int>(
83        sizeof(::llvm::detail::AlignmentCalcImpl<T>) - sizeof(T))
84  };
85#endif
86  enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
87  enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
88  enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
89  enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
90
91  enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
92  enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
93  enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
94  enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
95};
96
97#ifndef _MSC_VER
98template <typename T> constexpr unsigned AlignOf<T>::Alignment;
99#endif
100
101/// alignOf - A templated function that returns the minimum alignment of
102///  of a type.  This provides no extra functionality beyond the AlignOf
103///  class besides some cosmetic cleanliness.  Example usage:
104///  alignOf<int>() returns the alignment of an int.
105template <typename T>
106inline unsigned alignOf() { return AlignOf<T>::Alignment; }
107
108/// \struct AlignedCharArray
109/// \brief Helper for building an aligned character array type.
110///
111/// This template is used to explicitly build up a collection of aligned
112/// character array types. We have to build these up using a macro and explicit
113/// specialization to cope with old versions of MSVC and GCC where only an
114/// integer literal can be used to specify an alignment constraint. Once built
115/// up here, we can then begin to indirect between these using normal C++
116/// template parameters.
117
118// MSVC requires special handling here.
119#ifndef _MSC_VER
120
121#if __has_feature(cxx_alignas)
122template<std::size_t Alignment, std::size_t Size>
123struct AlignedCharArray {
124  alignas(Alignment) char buffer[Size];
125};
126
127#elif defined(__GNUC__) || defined(__IBM_ATTRIBUTES)
128/// \brief Create a type with an aligned char buffer.
129template<std::size_t Alignment, std::size_t Size>
130struct AlignedCharArray;
131
132#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
133  template<std::size_t Size> \
134  struct AlignedCharArray<x, Size> { \
135    __attribute__((aligned(x))) char buffer[Size]; \
136  };
137
138LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1)
139LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2)
140LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4)
141LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8)
142LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
143LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
144LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
145LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
146
147#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
148
149#else
150# error No supported align as directive.
151#endif
152
153#else // _MSC_VER
154
155/// \brief Create a type with an aligned char buffer.
156template<std::size_t Alignment, std::size_t Size>
157struct AlignedCharArray;
158
159// We provide special variations of this template for the most common
160// alignments because __declspec(align(...)) doesn't actually work when it is
161// a member of a by-value function argument in MSVC, even if the alignment
162// request is something reasonably like 8-byte or 16-byte. Note that we can't
163// even include the declspec with the union that forces the alignment because
164// MSVC warns on the existence of the declspec despite the union member forcing
165// proper alignment.
166
167template<std::size_t Size>
168struct AlignedCharArray<1, Size> {
169  union {
170    char aligned;
171    char buffer[Size];
172  };
173};
174
175template<std::size_t Size>
176struct AlignedCharArray<2, Size> {
177  union {
178    short aligned;
179    char buffer[Size];
180  };
181};
182
183template<std::size_t Size>
184struct AlignedCharArray<4, Size> {
185  union {
186    int aligned;
187    char buffer[Size];
188  };
189};
190
191template<std::size_t Size>
192struct AlignedCharArray<8, Size> {
193  union {
194    double aligned;
195    char buffer[Size];
196  };
197};
198
199
200// The rest of these are provided with a __declspec(align(...)) and we simply
201// can't pass them by-value as function arguments on MSVC.
202
203#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
204  template<std::size_t Size> \
205  struct AlignedCharArray<x, Size> { \
206    __declspec(align(x)) char buffer[Size]; \
207  };
208
209LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
210LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
211LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
212LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
213
214#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
215
216#endif // _MSC_VER
217
218namespace detail {
219template <typename T1,
220          typename T2 = char, typename T3 = char, typename T4 = char,
221          typename T5 = char, typename T6 = char, typename T7 = char,
222          typename T8 = char, typename T9 = char, typename T10 = char>
223class AlignerImpl {
224  T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10;
225
226  AlignerImpl() = delete;
227};
228
229template <typename T1,
230          typename T2 = char, typename T3 = char, typename T4 = char,
231          typename T5 = char, typename T6 = char, typename T7 = char,
232          typename T8 = char, typename T9 = char, typename T10 = char>
233union SizerImpl {
234  char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
235       arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
236       arr9[sizeof(T9)], arr10[sizeof(T10)];
237};
238} // end namespace detail
239
240/// \brief This union template exposes a suitably aligned and sized character
241/// array member which can hold elements of any of up to ten types.
242///
243/// These types may be arrays, structs, or any other types. The goal is to
244/// expose a char array buffer member which can be used as suitable storage for
245/// a placement new of any of these types. Support for more than ten types can
246/// be added at the cost of more boilerplate.
247template <typename T1,
248          typename T2 = char, typename T3 = char, typename T4 = char,
249          typename T5 = char, typename T6 = char, typename T7 = char,
250          typename T8 = char, typename T9 = char, typename T10 = char>
251struct AlignedCharArrayUnion : llvm::AlignedCharArray<
252    AlignOf<llvm::detail::AlignerImpl<T1, T2, T3, T4, T5,
253                                      T6, T7, T8, T9, T10> >::Alignment,
254    sizeof(::llvm::detail::SizerImpl<T1, T2, T3, T4, T5,
255                                     T6, T7, T8, T9, T10>)> {
256};
257} // end namespace llvm
258
259#endif // LLVM_SUPPORT_ALIGNOF_H
260