AlignOf.h revision 6656afb31a517944accc52a364fb5d1b98bffb4f
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
21namespace llvm {
22
23template <typename T>
24struct AlignmentCalcImpl {
25  char x;
26  T t;
27private:
28  AlignmentCalcImpl() {} // Never instantiate.
29};
30
31/// AlignOf - A templated class that contains an enum value representing
32///  the alignment of the template argument.  For example,
33///  AlignOf<int>::Alignment represents the alignment of type "int".  The
34///  alignment calculated is the minimum alignment, and not necessarily
35///  the "desired" alignment returned by GCC's __alignof__ (for example).  Note
36///  that because the alignment is an enum value, it can be used as a
37///  compile-time constant (e.g., for template instantiation).
38template <typename T>
39struct AlignOf {
40  enum { Alignment =
41         static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };
42
43  enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
44  enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
45  enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
46  enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
47
48  enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
49  enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
50  enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
51  enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
52
53};
54
55/// alignOf - A templated function that returns the minimum alignment of
56///  of a type.  This provides no extra functionality beyond the AlignOf
57///  class besides some cosmetic cleanliness.  Example usage:
58///  alignOf<int>() returns the alignment of an int.
59template <typename T>
60inline unsigned alignOf() { return AlignOf<T>::Alignment; }
61
62
63/// \brief Helper for building an aligned character array type.
64///
65/// This template is used to explicitly build up a collection of aligned
66/// character types. We have to build these up using a macro and explicit
67/// specialization to cope with old versions of MSVC and GCC where only an
68/// integer literal can be used to specify an alignment constraint. Once built
69/// up here, we can then begin to indirect between these using normal C++
70/// template parameters.
71template <size_t Alignment> struct AlignedCharArrayImpl {};
72template <> struct AlignedCharArrayImpl<0> {
73  typedef char type;
74};
75#if __has_feature(cxx_alignas)
76#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
77  template <> struct AlignedCharArrayImpl<x> { \
78    typedef char alignas(x) type; \
79  }
80#elif defined(__clang__) || defined(__GNUC__)
81#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
82  template <> struct AlignedCharArrayImpl<x> { \
83    typedef char type __attribute__((aligned(x))); \
84  }
85#elif defined(_MSC_VER)
86#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
87  template <> struct AlignedCharArrayImpl<x> { \
88    typedef __declspec(align(x)) char type; \
89  }
90#else
91# error No supported align as directive.
92#endif
93
94LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1);
95LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2);
96LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4);
97LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8);
98LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16);
99LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32);
100LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64);
101LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128);
102LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(512);
103LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1024);
104LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2048);
105LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4096);
106LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8192);
107// Any larger and MSVC complains.
108#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
109
110/// \brief This class template exposes a typedef for type containing a suitable
111/// aligned character array to hold elements of any of up to four types.
112///
113/// These types may be arrays, structs, or any other types. The goal is to
114/// produce a union type containing a character array which, when used, forms
115/// storage suitable to placement new any of these types over. Support for more
116/// than four types can be added at the cost of more boiler plate.
117template <typename T1,
118          typename T2 = char, typename T3 = char, typename T4 = char>
119class AlignedCharArray {
120  class AlignerImpl {
121    T1 t1; T2 t2; T3 t3; T4 t4;
122
123    AlignerImpl(); // Never defined or instantiated.
124  };
125  union SizerImpl {
126    char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)];
127  };
128
129public:
130  // Sadly, Clang and GCC both fail to align a character array properly even
131  // with an explicit alignment attribute. To work around this, we union
132  // the character array that will actually be used with a struct that contains
133  // a single aligned character member. Tests seem to indicate that both Clang
134  // and GCC will properly register the alignment of a struct containing an
135  // aligned member, and this alignment should carry over to the character
136  // array in the union.
137  union union_type {
138    // This is the only member of the union which should be used by clients:
139    char buffer[sizeof(SizerImpl)];
140
141    // This member of the union only exists to force the alignment.
142    struct {
143      typename llvm::AlignedCharArrayImpl<AlignOf<AlignerImpl>::Alignment>::type
144        nonce_inner_member;
145    } nonce_member;
146  };
147};
148
149} // end namespace llvm
150#endif
151