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