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 <cassert> 31 #include "llvm/ADT/DenseMapInfo.h" 32 #include "llvm/CodeGen/MachineValueType.h" 33 34 namespace llvm { 35 36 class DataLayout; 37 class Type; 38 class raw_ostream; 39 40 class LLT { 41 public: 42 enum TypeKind : uint16_t { 43 Invalid, 44 Scalar, 45 Pointer, 46 Vector, 47 }; 48 49 /// Get a low-level scalar or aggregate "bag of bits". 50 static LLT scalar(unsigned SizeInBits) { 51 assert(SizeInBits > 0 && "invalid scalar size"); 52 return LLT{Scalar, 1, SizeInBits}; 53 } 54 55 /// Get a low-level pointer in the given address space (defaulting to 0). 56 static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) { 57 return LLT{Pointer, AddressSpace, SizeInBits}; 58 } 59 60 /// Get a low-level vector of some number of elements and element width. 61 /// \p NumElements must be at least 2. 62 static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { 63 assert(NumElements > 1 && "invalid number of vector elements"); 64 return LLT{Vector, NumElements, ScalarSizeInBits}; 65 } 66 67 /// Get a low-level vector of some number of elements and element type. 68 static LLT vector(uint16_t NumElements, LLT ScalarTy) { 69 assert(NumElements > 1 && "invalid number of vector elements"); 70 assert(ScalarTy.isScalar() && "invalid vector element type"); 71 return LLT{Vector, NumElements, ScalarTy.getSizeInBits()}; 72 } 73 74 explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits) 75 : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) { 76 assert((Kind != Vector || ElementsOrAddrSpace > 1) && 77 "invalid number of vector elements"); 78 } 79 80 explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {} 81 82 explicit LLT(MVT VT); 83 84 bool isValid() const { return Kind != Invalid; } 85 86 bool isScalar() const { return Kind == Scalar; } 87 88 bool isPointer() const { return Kind == Pointer; } 89 90 bool isVector() const { return Kind == Vector; } 91 92 /// Returns the number of elements in a vector LLT. Must only be called on 93 /// vector types. 94 uint16_t getNumElements() const { 95 assert(isVector() && "cannot get number of elements on scalar/aggregate"); 96 return ElementsOrAddrSpace; 97 } 98 99 /// Returns the total size of the type. Must only be called on sized types. 100 unsigned getSizeInBits() const { 101 if (isPointer() || isScalar()) 102 return SizeInBits; 103 return SizeInBits * ElementsOrAddrSpace; 104 } 105 106 unsigned getScalarSizeInBits() const { 107 return SizeInBits; 108 } 109 110 unsigned getAddressSpace() const { 111 assert(isPointer() && "cannot get address space of non-pointer type"); 112 return ElementsOrAddrSpace; 113 } 114 115 /// Returns the vector's element type. Only valid for vector types. 116 LLT getElementType() const { 117 assert(isVector() && "cannot get element type of scalar/aggregate"); 118 return scalar(SizeInBits); 119 } 120 121 /// Get a low-level type with half the size of the original, by halving the 122 /// size of the scalar type involved. For example `s32` will become `s16`, 123 /// `<2 x s32>` will become `<2 x s16>`. 124 LLT halfScalarSize() const { 125 assert(!isPointer() && getScalarSizeInBits() > 1 && 126 getScalarSizeInBits() % 2 == 0 && "cannot half size of this type"); 127 return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2}; 128 } 129 130 /// Get a low-level type with twice the size of the original, by doubling the 131 /// size of the scalar type involved. For example `s32` will become `s64`, 132 /// `<2 x s32>` will become `<2 x s64>`. 133 LLT doubleScalarSize() const { 134 assert(!isPointer() && "cannot change size of this type"); 135 return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2}; 136 } 137 138 /// Get a low-level type with half the size of the original, by halving the 139 /// number of vector elements of the scalar type involved. The source must be 140 /// a vector type with an even number of elements. For example `<4 x s32>` 141 /// will become `<2 x s32>`, `<2 x s32>` will become `s32`. 142 LLT halfElements() const { 143 assert(isVector() && ElementsOrAddrSpace % 2 == 0 && 144 "cannot half odd vector"); 145 if (ElementsOrAddrSpace == 2) 146 return scalar(SizeInBits); 147 148 return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2), 149 SizeInBits}; 150 } 151 152 /// Get a low-level type with twice the size of the original, by doubling the 153 /// number of vector elements of the scalar type involved. The source must be 154 /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling 155 /// the number of elements in sN produces <2 x sN>. 156 LLT doubleElements() const { 157 assert(!isPointer() && "cannot double elements in pointer"); 158 return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2), 159 SizeInBits}; 160 } 161 162 void print(raw_ostream &OS) const; 163 164 bool operator==(const LLT &RHS) const { 165 return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits && 166 ElementsOrAddrSpace == RHS.ElementsOrAddrSpace; 167 } 168 169 bool operator!=(const LLT &RHS) const { return !(*this == RHS); } 170 171 friend struct DenseMapInfo<LLT>; 172 private: 173 unsigned SizeInBits; 174 uint16_t ElementsOrAddrSpace; 175 TypeKind Kind; 176 }; 177 178 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { 179 Ty.print(OS); 180 return OS; 181 } 182 183 template<> struct DenseMapInfo<LLT> { 184 static inline LLT getEmptyKey() { 185 return LLT{LLT::Invalid, 0, -1u}; 186 } 187 static inline LLT getTombstoneKey() { 188 return LLT{LLT::Invalid, 0, -2u}; 189 } 190 static inline unsigned getHashValue(const LLT &Ty) { 191 uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) | 192 ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind; 193 return DenseMapInfo<uint64_t>::getHashValue(Val); 194 } 195 static bool isEqual(const LLT &LHS, const LLT &RHS) { 196 return LHS == RHS; 197 } 198 }; 199 200 } 201 202 #endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H 203