1193323Sed//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
2193323Sed//
3193323Sed//                     The LLVM Compiler Infrastructure
4193323Sed//
5193323Sed// This file is distributed under the University of Illinois Open Source
6193323Sed// License. See LICENSE.TXT for details.
7193323Sed//
8193323Sed//===----------------------------------------------------------------------===//
9193323Sed//
10193323Sed// This file defines the AlignOf function that computes alignments for
11193323Sed// arbitrary types.
12193323Sed//
13193323Sed//===----------------------------------------------------------------------===//
14193323Sed
15193323Sed#ifndef LLVM_SUPPORT_ALIGNOF_H
16193323Sed#define LLVM_SUPPORT_ALIGNOF_H
17193323Sed
18239462Sdim#include "llvm/Support/Compiler.h"
19239462Sdim#include <cstddef>
20239462Sdim
21193323Sednamespace llvm {
22193323Sedtemplate <typename T>
23193323Sedstruct AlignmentCalcImpl {
24193323Sed  char x;
25193323Sed  T t;
26193323Sedprivate:
27193323Sed  AlignmentCalcImpl() {} // Never instantiate.
28193323Sed};
29193323Sed
30193323Sed/// AlignOf - A templated class that contains an enum value representing
31193323Sed///  the alignment of the template argument.  For example,
32193323Sed///  AlignOf<int>::Alignment represents the alignment of type "int".  The
33193323Sed///  alignment calculated is the minimum alignment, and not necessarily
34193323Sed///  the "desired" alignment returned by GCC's __alignof__ (for example).  Note
35193323Sed///  that because the alignment is an enum value, it can be used as a
36193323Sed///  compile-time constant (e.g., for template instantiation).
37193323Sedtemplate <typename T>
38193323Sedstruct AlignOf {
39193323Sed  enum { Alignment =
40193323Sed         static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };
41193323Sed
42193323Sed  enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
43193323Sed  enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
44193323Sed  enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
45193323Sed  enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
46193323Sed
47193323Sed  enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
48193323Sed  enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
49193323Sed  enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
50193323Sed  enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
51193323Sed};
52193323Sed
53218893Sdim/// alignOf - A templated function that returns the minimum alignment of
54193323Sed///  of a type.  This provides no extra functionality beyond the AlignOf
55193323Sed///  class besides some cosmetic cleanliness.  Example usage:
56218893Sdim///  alignOf<int>() returns the alignment of an int.
57193323Sedtemplate <typename T>
58239462Sdiminline unsigned alignOf() { return AlignOf<T>::Alignment; }
59193323Sed
60249423Sdim/// \struct AlignedCharArray
61239462Sdim/// \brief Helper for building an aligned character array type.
62239462Sdim///
63239462Sdim/// This template is used to explicitly build up a collection of aligned
64249423Sdim/// character array types. We have to build these up using a macro and explicit
65239462Sdim/// specialization to cope with old versions of MSVC and GCC where only an
66239462Sdim/// integer literal can be used to specify an alignment constraint. Once built
67239462Sdim/// up here, we can then begin to indirect between these using normal C++
68239462Sdim/// template parameters.
69243830Sdim
70243830Sdim// MSVC requires special handling here.
71243830Sdim#ifndef _MSC_VER
72243830Sdim
73239462Sdim#if __has_feature(cxx_alignas)
74249423Sdimtemplate<std::size_t Alignment, std::size_t Size>
75249423Sdimstruct AlignedCharArray {
76249423Sdim  alignas(Alignment) char buffer[Size];
77249423Sdim};
78249423Sdim
79243830Sdim#elif defined(__GNUC__) || defined(__IBM_ATTRIBUTES)
80249423Sdim/// \brief Create a type with an aligned char buffer.
81249423Sdimtemplate<std::size_t Alignment, std::size_t Size>
82249423Sdimstruct AlignedCharArray;
83249423Sdim
84239462Sdim#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
85249423Sdim  template<std::size_t Size> \
86249423Sdim  struct AlignedCharArray<x, Size> { \
87249423Sdim    __attribute__((aligned(x))) char buffer[Size]; \
88249423Sdim  };
89249423Sdim
90249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1)
91249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2)
92249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4)
93249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8)
94249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
95249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
96249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
97249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
98249423Sdim
99249423Sdim#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
100249423Sdim
101239462Sdim#else
102239462Sdim# error No supported align as directive.
103239462Sdim#endif
104239462Sdim
105249423Sdim#else // _MSC_VER
106243830Sdim
107249423Sdim/// \brief Create a type with an aligned char buffer.
108249423Sdimtemplate<std::size_t Alignment, std::size_t Size>
109249423Sdimstruct AlignedCharArray;
110243830Sdim
111243830Sdim// We provide special variations of this template for the most common
112243830Sdim// alignments because __declspec(align(...)) doesn't actually work when it is
113243830Sdim// a member of a by-value function argument in MSVC, even if the alignment
114249423Sdim// request is something reasonably like 8-byte or 16-byte. Note that we can't
115249423Sdim// even include the declspec with the union that forces the alignment because
116249423Sdim// MSVC warns on the existence of the declspec despite the union member forcing
117249423Sdim// proper alignment.
118243830Sdim
119249423Sdimtemplate<std::size_t Size>
120249423Sdimstruct AlignedCharArray<1, Size> {
121249423Sdim  union {
122249423Sdim    char aligned;
123249423Sdim    char buffer[Size];
124249423Sdim  };
125249423Sdim};
126249423Sdim
127249423Sdimtemplate<std::size_t Size>
128249423Sdimstruct AlignedCharArray<2, Size> {
129249423Sdim  union {
130249423Sdim    short aligned;
131249423Sdim    char buffer[Size];
132249423Sdim  };
133249423Sdim};
134249423Sdim
135249423Sdimtemplate<std::size_t Size>
136249423Sdimstruct AlignedCharArray<4, Size> {
137249423Sdim  union {
138249423Sdim    int aligned;
139249423Sdim    char buffer[Size];
140249423Sdim  };
141249423Sdim};
142249423Sdim
143249423Sdimtemplate<std::size_t Size>
144249423Sdimstruct AlignedCharArray<8, Size> {
145249423Sdim  union {
146249423Sdim    double aligned;
147249423Sdim    char buffer[Size];
148249423Sdim  };
149249423Sdim};
150249423Sdim
151249423Sdim
152249423Sdim// The rest of these are provided with a __declspec(align(...)) and we simply
153249423Sdim// can't pass them by-value as function arguments on MSVC.
154249423Sdim
155243830Sdim#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
156249423Sdim  template<std::size_t Size> \
157249423Sdim  struct AlignedCharArray<x, Size> { \
158249423Sdim    __declspec(align(x)) char buffer[Size]; \
159249423Sdim  };
160249423Sdim
161249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
162249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
163249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
164249423SdimLLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
165249423Sdim
166239462Sdim#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
167239462Sdim
168243830Sdim#endif // _MSC_VER
169243830Sdim
170249423Sdimnamespace detail {
171249423Sdimtemplate <typename T1,
172249423Sdim          typename T2 = char, typename T3 = char, typename T4 = char,
173249423Sdim          typename T5 = char, typename T6 = char, typename T7 = char>
174249423Sdimclass AlignerImpl {
175249423Sdim  T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7;
176249423Sdim
177249423Sdim  AlignerImpl(); // Never defined or instantiated.
178249423Sdim};
179249423Sdim
180249423Sdimtemplate <typename T1,
181249423Sdim          typename T2 = char, typename T3 = char, typename T4 = char,
182249423Sdim          typename T5 = char, typename T6 = char, typename T7 = char>
183249423Sdimunion SizerImpl {
184249423Sdim  char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
185249423Sdim       arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)];
186249423Sdim};
187249423Sdim} // end namespace detail
188249423Sdim
189239462Sdim/// \brief This union template exposes a suitably aligned and sized character
190239462Sdim/// array member which can hold elements of any of up to four types.
191239462Sdim///
192239462Sdim/// These types may be arrays, structs, or any other types. The goal is to
193249423Sdim/// expose a char array buffer member which can be used as suitable storage for
194249423Sdim/// a placement new of any of these types. Support for more than seven types can
195249423Sdim/// be added at the cost of more boiler plate.
196239462Sdimtemplate <typename T1,
197249423Sdim          typename T2 = char, typename T3 = char, typename T4 = char,
198249423Sdim          typename T5 = char, typename T6 = char, typename T7 = char>
199249423Sdimstruct AlignedCharArrayUnion : llvm::AlignedCharArray<
200249423Sdim    AlignOf<detail::AlignerImpl<T1, T2, T3, T4, T5, T6, T7> >::Alignment,
201249423Sdim    sizeof(detail::SizerImpl<T1, T2, T3, T4, T5, T6, T7>)> {
202239462Sdim};
203193323Sed} // end namespace llvm
204193323Sed#endif
205