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