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