Home | History | Annotate | Download | only in Support
      1 //== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- 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 /// Implement a low-level type suitable for MachineInstr level instruction
     11 /// selection.
     12 ///
     13 /// For a type attached to a MachineInstr, we only care about 2 details: total
     14 /// size and the number of vector lanes (if any). Accordingly, there are 4
     15 /// possible valid type-kinds:
     16 ///
     17 ///    * `sN` for scalars and aggregates
     18 ///    * `<N x sM>` for vectors, which must have at least 2 elements.
     19 ///    * `pN` for pointers
     20 ///
     21 /// Other information required for correct selection is expected to be carried
     22 /// by the opcode, or non-type flags. For example the distinction between G_ADD
     23 /// and G_FADD for int/float or fast-math flags.
     24 //
     25 //===----------------------------------------------------------------------===//
     26 
     27 #ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
     28 #define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
     29 
     30 #include "llvm/ADT/DenseMapInfo.h"
     31 #include "llvm/CodeGen/MachineValueType.h"
     32 #include <cassert>
     33 
     34 namespace llvm {
     35 
     36 class DataLayout;
     37 class Type;
     38 class raw_ostream;
     39 
     40 class LLT {
     41 public:
     42   /// Get a low-level scalar or aggregate "bag of bits".
     43   static LLT scalar(unsigned SizeInBits) {
     44     assert(SizeInBits > 0 && "invalid scalar size");
     45     return LLT{/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0,
     46                SizeInBits, /*AddressSpace=*/0};
     47   }
     48 
     49   /// Get a low-level pointer in the given address space (defaulting to 0).
     50   static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) {
     51     assert(SizeInBits > 0 && "invalid pointer size");
     52     return LLT{/*isPointer=*/true, /*isVector=*/false, /*NumElements=*/0,
     53                SizeInBits, AddressSpace};
     54   }
     55 
     56   /// Get a low-level vector of some number of elements and element width.
     57   /// \p NumElements must be at least 2.
     58   static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) {
     59     assert(NumElements > 1 && "invalid number of vector elements");
     60     assert(ScalarSizeInBits > 0 && "invalid vector element size");
     61     return LLT{/*isPointer=*/false, /*isVector=*/true, NumElements,
     62                ScalarSizeInBits, /*AddressSpace=*/0};
     63   }
     64 
     65   /// Get a low-level vector of some number of elements and element type.
     66   static LLT vector(uint16_t NumElements, LLT ScalarTy) {
     67     assert(NumElements > 1 && "invalid number of vector elements");
     68     assert(!ScalarTy.isVector() && "invalid vector element type");
     69     return LLT{ScalarTy.isPointer(), /*isVector=*/true, NumElements,
     70                ScalarTy.getSizeInBits(),
     71                ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
     72   }
     73 
     74   explicit LLT(bool isPointer, bool isVector, uint16_t NumElements,
     75                unsigned SizeInBits, unsigned AddressSpace) {
     76     init(isPointer, isVector, NumElements, SizeInBits, AddressSpace);
     77   }
     78   explicit LLT() : IsPointer(false), IsVector(false), RawData(0) {}
     79 
     80   explicit LLT(MVT VT);
     81 
     82   bool isValid() const { return RawData != 0; }
     83 
     84   bool isScalar() const { return isValid() && !IsPointer && !IsVector; }
     85 
     86   bool isPointer() const { return isValid() && IsPointer && !IsVector; }
     87 
     88   bool isVector() const { return isValid() && IsVector; }
     89 
     90   /// Returns the number of elements in a vector LLT. Must only be called on
     91   /// vector types.
     92   uint16_t getNumElements() const {
     93     assert(IsVector && "cannot get number of elements on scalar/aggregate");
     94     if (!IsPointer)
     95       return getFieldValue(VectorElementsFieldInfo);
     96     else
     97       return getFieldValue(PointerVectorElementsFieldInfo);
     98   }
     99 
    100   /// Returns the total size of the type. Must only be called on sized types.
    101   unsigned getSizeInBits() const {
    102     if (isPointer() || isScalar())
    103       return getScalarSizeInBits();
    104     return getScalarSizeInBits() * getNumElements();
    105   }
    106 
    107   unsigned getScalarSizeInBits() const {
    108     assert(RawData != 0 && "Invalid Type");
    109     if (!IsVector) {
    110       if (!IsPointer)
    111         return getFieldValue(ScalarSizeFieldInfo);
    112       else
    113         return getFieldValue(PointerSizeFieldInfo);
    114     } else {
    115       if (!IsPointer)
    116         return getFieldValue(VectorSizeFieldInfo);
    117       else
    118         return getFieldValue(PointerVectorSizeFieldInfo);
    119     }
    120   }
    121 
    122   unsigned getAddressSpace() const {
    123     assert(RawData != 0 && "Invalid Type");
    124     assert(IsPointer && "cannot get address space of non-pointer type");
    125     if (!IsVector)
    126       return getFieldValue(PointerAddressSpaceFieldInfo);
    127     else
    128       return getFieldValue(PointerVectorAddressSpaceFieldInfo);
    129   }
    130 
    131   /// Returns the vector's element type. Only valid for vector types.
    132   LLT getElementType() const {
    133     assert(isVector() && "cannot get element type of scalar/aggregate");
    134     if (IsPointer)
    135       return pointer(getAddressSpace(), getScalarSizeInBits());
    136     else
    137       return scalar(getScalarSizeInBits());
    138   }
    139 
    140   /// Get a low-level type with half the size of the original, by halving the
    141   /// size of the scalar type involved. For example `s32` will become `s16`,
    142   /// `<2 x s32>` will become `<2 x s16>`.
    143   LLT halfScalarSize() const {
    144     assert(!IsPointer && getScalarSizeInBits() > 1 &&
    145            getScalarSizeInBits() % 2 == 0 && "cannot half size of this type");
    146     return LLT{/*isPointer=*/false, IsVector ? true : false,
    147                IsVector ? getNumElements() : (uint16_t)0,
    148                getScalarSizeInBits() / 2, /*AddressSpace=*/0};
    149   }
    150 
    151   /// Get a low-level type with twice the size of the original, by doubling the
    152   /// size of the scalar type involved. For example `s32` will become `s64`,
    153   /// `<2 x s32>` will become `<2 x s64>`.
    154   LLT doubleScalarSize() const {
    155     assert(!IsPointer && "cannot change size of this type");
    156     return LLT{/*isPointer=*/false, IsVector ? true : false,
    157                IsVector ? getNumElements() : (uint16_t)0,
    158                getScalarSizeInBits() * 2, /*AddressSpace=*/0};
    159   }
    160 
    161   /// Get a low-level type with half the size of the original, by halving the
    162   /// number of vector elements of the scalar type involved. The source must be
    163   /// a vector type with an even number of elements. For example `<4 x s32>`
    164   /// will become `<2 x s32>`, `<2 x s32>` will become `s32`.
    165   LLT halfElements() const {
    166     assert(isVector() && getNumElements() % 2 == 0 && "cannot half odd vector");
    167     if (getNumElements() == 2)
    168       return scalar(getScalarSizeInBits());
    169 
    170     return LLT{/*isPointer=*/false, /*isVector=*/true,
    171                (uint16_t)(getNumElements() / 2), getScalarSizeInBits(),
    172                /*AddressSpace=*/0};
    173   }
    174 
    175   /// Get a low-level type with twice the size of the original, by doubling the
    176   /// number of vector elements of the scalar type involved. The source must be
    177   /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling
    178   /// the number of elements in sN produces <2 x sN>.
    179   LLT doubleElements() const {
    180     return LLT{IsPointer ? true : false, /*isVector=*/true,
    181                (uint16_t)(getNumElements() * 2), getScalarSizeInBits(),
    182                IsPointer ? getAddressSpace() : 0};
    183   }
    184 
    185   void print(raw_ostream &OS) const;
    186 
    187   bool operator==(const LLT &RHS) const {
    188     return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
    189            RHS.RawData == RawData;
    190   }
    191 
    192   bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
    193 
    194   friend struct DenseMapInfo<LLT>;
    195 
    196 private:
    197   /// LLT is packed into 64 bits as follows:
    198   /// isPointer : 1
    199   /// isVector  : 1
    200   /// with 62 bits remaining for Kind-specific data, packed in bitfields
    201   /// as described below. As there isn't a simple portable way to pack bits
    202   /// into bitfields, here the different fields in the packed structure is
    203   /// described in static const *Field variables. Each of these variables
    204   /// is a 2-element array, with the first element describing the bitfield size
    205   /// and the second element describing the bitfield offset.
    206   typedef int BitFieldInfo[2];
    207   ///
    208   /// This is how the bitfields are packed per Kind:
    209   /// * Invalid:
    210   ///   gets encoded as RawData == 0, as that is an invalid encoding, since for
    211   ///   valid encodings, SizeInBits/SizeOfElement must be larger than 0.
    212   /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
    213   ///   SizeInBits: 32;
    214   static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 0};
    215   /// * Pointer (isPointer == 1 && isVector == 0):
    216   ///   SizeInBits: 16;
    217   ///   AddressSpace: 23;
    218   static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 0};
    219   static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{
    220       23, PointerSizeFieldInfo[0] + PointerSizeFieldInfo[1]};
    221   /// * Vector-of-non-pointer (isPointer == 0 && isVector == 1):
    222   ///   NumElements: 16;
    223   ///   SizeOfElement: 32;
    224   static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 0};
    225   static const constexpr BitFieldInfo VectorSizeFieldInfo{
    226       32, VectorElementsFieldInfo[0] + VectorElementsFieldInfo[1]};
    227   /// * Vector-of-pointer (isPointer == 1 && isVector == 1):
    228   ///   NumElements: 16;
    229   ///   SizeOfElement: 16;
    230   ///   AddressSpace: 23;
    231   static const constexpr BitFieldInfo PointerVectorElementsFieldInfo{16, 0};
    232   static const constexpr BitFieldInfo PointerVectorSizeFieldInfo{
    233       16,
    234       PointerVectorElementsFieldInfo[1] + PointerVectorElementsFieldInfo[0]};
    235   static const constexpr BitFieldInfo PointerVectorAddressSpaceFieldInfo{
    236       23, PointerVectorSizeFieldInfo[1] + PointerVectorSizeFieldInfo[0]};
    237 
    238   uint64_t IsPointer : 1;
    239   uint64_t IsVector : 1;
    240   uint64_t RawData : 62;
    241 
    242   static uint64_t getMask(const BitFieldInfo FieldInfo) {
    243     const int FieldSizeInBits = FieldInfo[0];
    244     return (((uint64_t)1) << FieldSizeInBits) - 1;
    245   }
    246   static uint64_t maskAndShift(uint64_t Val, uint64_t Mask, uint8_t Shift) {
    247     assert(Val <= Mask && "Value too large for field");
    248     return (Val & Mask) << Shift;
    249   }
    250   static uint64_t maskAndShift(uint64_t Val, const BitFieldInfo FieldInfo) {
    251     return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]);
    252   }
    253   uint64_t getFieldValue(const BitFieldInfo FieldInfo) const {
    254     return getMask(FieldInfo) & (RawData >> FieldInfo[1]);
    255   }
    256 
    257   void init(bool IsPointer, bool IsVector, uint16_t NumElements,
    258             unsigned SizeInBits, unsigned AddressSpace) {
    259     this->IsPointer = IsPointer;
    260     this->IsVector = IsVector;
    261     if (!IsVector) {
    262       if (!IsPointer)
    263         RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo);
    264       else
    265         RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) |
    266                   maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo);
    267     } else {
    268       assert(NumElements > 1 && "invalid number of vector elements");
    269       if (!IsPointer)
    270         RawData = maskAndShift(NumElements, VectorElementsFieldInfo) |
    271                   maskAndShift(SizeInBits, VectorSizeFieldInfo);
    272       else
    273         RawData =
    274             maskAndShift(NumElements, PointerVectorElementsFieldInfo) |
    275             maskAndShift(SizeInBits, PointerVectorSizeFieldInfo) |
    276             maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo);
    277     }
    278   }
    279 };
    280 
    281 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
    282   Ty.print(OS);
    283   return OS;
    284 }
    285 
    286 template<> struct DenseMapInfo<LLT> {
    287   static inline LLT getEmptyKey() {
    288     LLT Invalid;
    289     Invalid.IsPointer = true;
    290     return Invalid;
    291   }
    292   static inline LLT getTombstoneKey() {
    293     LLT Invalid;
    294     Invalid.IsVector = true;
    295     return Invalid;
    296   }
    297   static inline unsigned getHashValue(const LLT &Ty) {
    298     uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 |
    299                    ((uint64_t)Ty.IsVector);
    300     return DenseMapInfo<uint64_t>::getHashValue(Val);
    301   }
    302   static bool isEqual(const LLT &LHS, const LLT &RHS) {
    303     return LHS == RHS;
    304   }
    305 };
    306 
    307 }
    308 
    309 #endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
    310