1 //== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- C++ -*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 /// Implement a low-level type suitable for MachineInstr level instruction 10 /// selection. 11 /// 12 /// For a type attached to a MachineInstr, we only care about 2 details: total 13 /// size and the number of vector lanes (if any). Accordingly, there are 4 14 /// possible valid type-kinds: 15 /// 16 /// * `sN` for scalars and aggregates 17 /// * `<N x sM>` for vectors, which must have at least 2 elements. 18 /// * `pN` for pointers 19 /// 20 /// Other information required for correct selection is expected to be carried 21 /// by the opcode, or non-type flags. For example the distinction between G_ADD 22 /// and G_FADD for int/float or fast-math flags. 23 // 24 //===----------------------------------------------------------------------===// 25 26 #ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H 27 #define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H 28 29 #include "llvm/ADT/DenseMapInfo.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/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". scalar(unsigned SizeInBits)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. pointer(unsigned AddressSpace,unsigned SizeInBits)50 static LLT pointer(unsigned 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. vector(uint16_t NumElements,unsigned ScalarSizeInBits)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. vector(uint16_t NumElements,LLT ScalarTy)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 scalarOrVector(uint16_t NumElements,LLT ScalarTy)74 static LLT scalarOrVector(uint16_t NumElements, LLT ScalarTy) { 75 return NumElements == 1 ? ScalarTy : LLT::vector(NumElements, ScalarTy); 76 } 77 scalarOrVector(uint16_t NumElements,unsigned ScalarSize)78 static LLT scalarOrVector(uint16_t NumElements, unsigned ScalarSize) { 79 return scalarOrVector(NumElements, LLT::scalar(ScalarSize)); 80 } 81 LLT(bool isPointer,bool isVector,uint16_t NumElements,unsigned SizeInBits,unsigned AddressSpace)82 explicit LLT(bool isPointer, bool isVector, uint16_t NumElements, 83 unsigned SizeInBits, unsigned AddressSpace) { 84 init(isPointer, isVector, NumElements, SizeInBits, AddressSpace); 85 } LLT()86 explicit LLT() : IsPointer(false), IsVector(false), RawData(0) {} 87 88 explicit LLT(MVT VT); 89 isValid()90 bool isValid() const { return RawData != 0; } 91 isScalar()92 bool isScalar() const { return isValid() && !IsPointer && !IsVector; } 93 isPointer()94 bool isPointer() const { return isValid() && IsPointer && !IsVector; } 95 isVector()96 bool isVector() const { return isValid() && IsVector; } 97 98 /// Returns the number of elements in a vector LLT. Must only be called on 99 /// vector types. getNumElements()100 uint16_t getNumElements() const { 101 assert(IsVector && "cannot get number of elements on scalar/aggregate"); 102 if (!IsPointer) 103 return getFieldValue(VectorElementsFieldInfo); 104 else 105 return getFieldValue(PointerVectorElementsFieldInfo); 106 } 107 108 /// Returns the total size of the type. Must only be called on sized types. getSizeInBits()109 unsigned getSizeInBits() const { 110 if (isPointer() || isScalar()) 111 return getScalarSizeInBits(); 112 return getScalarSizeInBits() * getNumElements(); 113 } 114 115 /// Returns the total size of the type in bytes, i.e. number of whole bytes 116 /// needed to represent the size in bits. Must only be called on sized types. getSizeInBytes()117 unsigned getSizeInBytes() const { 118 return (getSizeInBits() + 7) / 8; 119 } 120 getScalarType()121 LLT getScalarType() const { 122 return isVector() ? getElementType() : *this; 123 } 124 125 /// If this type is a vector, return a vector with the same number of elements 126 /// but the new element type. Otherwise, return the new element type. changeElementType(LLT NewEltTy)127 LLT changeElementType(LLT NewEltTy) const { 128 return isVector() ? LLT::vector(getNumElements(), NewEltTy) : NewEltTy; 129 } 130 131 /// If this type is a vector, return a vector with the same number of elements 132 /// but the new element size. Otherwise, return the new element type. Invalid 133 /// for pointer types. For pointer types, use changeElementType. changeElementSize(unsigned NewEltSize)134 LLT changeElementSize(unsigned NewEltSize) const { 135 assert(!getScalarType().isPointer() && 136 "invalid to directly change element size for pointers"); 137 return isVector() ? LLT::vector(getNumElements(), NewEltSize) 138 : LLT::scalar(NewEltSize); 139 } 140 141 /// Return a vector or scalar with the same element type and the new number of 142 /// elements. changeNumElements(unsigned NewNumElts)143 LLT changeNumElements(unsigned NewNumElts) const { 144 return LLT::scalarOrVector(NewNumElts, getScalarType()); 145 } 146 147 /// Return a type that is \p Factor times smaller. Reduces the number of 148 /// elements if this is a vector, or the bitwidth for scalar/pointers. Does 149 /// not attempt to handle cases that aren't evenly divisible. divide(int Factor)150 LLT divide(int Factor) const { 151 assert(Factor != 1); 152 if (isVector()) { 153 assert(getNumElements() % Factor == 0); 154 return scalarOrVector(getNumElements() / Factor, getElementType()); 155 } 156 157 assert(getSizeInBits() % Factor == 0); 158 return scalar(getSizeInBits() / Factor); 159 } 160 isByteSized()161 bool isByteSized() const { return (getSizeInBits() & 7) == 0; } 162 getScalarSizeInBits()163 unsigned getScalarSizeInBits() const { 164 assert(RawData != 0 && "Invalid Type"); 165 if (!IsVector) { 166 if (!IsPointer) 167 return getFieldValue(ScalarSizeFieldInfo); 168 else 169 return getFieldValue(PointerSizeFieldInfo); 170 } else { 171 if (!IsPointer) 172 return getFieldValue(VectorSizeFieldInfo); 173 else 174 return getFieldValue(PointerVectorSizeFieldInfo); 175 } 176 } 177 getAddressSpace()178 unsigned getAddressSpace() const { 179 assert(RawData != 0 && "Invalid Type"); 180 assert(IsPointer && "cannot get address space of non-pointer type"); 181 if (!IsVector) 182 return getFieldValue(PointerAddressSpaceFieldInfo); 183 else 184 return getFieldValue(PointerVectorAddressSpaceFieldInfo); 185 } 186 187 /// Returns the vector's element type. Only valid for vector types. getElementType()188 LLT getElementType() const { 189 assert(isVector() && "cannot get element type of scalar/aggregate"); 190 if (IsPointer) 191 return pointer(getAddressSpace(), getScalarSizeInBits()); 192 else 193 return scalar(getScalarSizeInBits()); 194 } 195 196 void print(raw_ostream &OS) const; 197 198 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) dump()199 LLVM_DUMP_METHOD void dump() const { 200 print(dbgs()); 201 dbgs() << '\n'; 202 } 203 #endif 204 205 bool operator==(const LLT &RHS) const { 206 return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector && 207 RHS.RawData == RawData; 208 } 209 210 bool operator!=(const LLT &RHS) const { return !(*this == RHS); } 211 212 friend struct DenseMapInfo<LLT>; 213 friend class GISelInstProfileBuilder; 214 215 private: 216 /// LLT is packed into 64 bits as follows: 217 /// isPointer : 1 218 /// isVector : 1 219 /// with 62 bits remaining for Kind-specific data, packed in bitfields 220 /// as described below. As there isn't a simple portable way to pack bits 221 /// into bitfields, here the different fields in the packed structure is 222 /// described in static const *Field variables. Each of these variables 223 /// is a 2-element array, with the first element describing the bitfield size 224 /// and the second element describing the bitfield offset. 225 typedef int BitFieldInfo[2]; 226 /// 227 /// This is how the bitfields are packed per Kind: 228 /// * Invalid: 229 /// gets encoded as RawData == 0, as that is an invalid encoding, since for 230 /// valid encodings, SizeInBits/SizeOfElement must be larger than 0. 231 /// * Non-pointer scalar (isPointer == 0 && isVector == 0): 232 /// SizeInBits: 32; 233 static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 0}; 234 /// * Pointer (isPointer == 1 && isVector == 0): 235 /// SizeInBits: 16; 236 /// AddressSpace: 24; 237 static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 0}; 238 static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{ 239 24, PointerSizeFieldInfo[0] + PointerSizeFieldInfo[1]}; 240 /// * Vector-of-non-pointer (isPointer == 0 && isVector == 1): 241 /// NumElements: 16; 242 /// SizeOfElement: 32; 243 static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 0}; 244 static const constexpr BitFieldInfo VectorSizeFieldInfo{ 245 32, VectorElementsFieldInfo[0] + VectorElementsFieldInfo[1]}; 246 /// * Vector-of-pointer (isPointer == 1 && isVector == 1): 247 /// NumElements: 16; 248 /// SizeOfElement: 16; 249 /// AddressSpace: 24; 250 static const constexpr BitFieldInfo PointerVectorElementsFieldInfo{16, 0}; 251 static const constexpr BitFieldInfo PointerVectorSizeFieldInfo{ 252 16, 253 PointerVectorElementsFieldInfo[1] + PointerVectorElementsFieldInfo[0]}; 254 static const constexpr BitFieldInfo PointerVectorAddressSpaceFieldInfo{ 255 24, PointerVectorSizeFieldInfo[1] + PointerVectorSizeFieldInfo[0]}; 256 257 uint64_t IsPointer : 1; 258 uint64_t IsVector : 1; 259 uint64_t RawData : 62; 260 261 static uint64_t getMask(const BitFieldInfo FieldInfo) { 262 const int FieldSizeInBits = FieldInfo[0]; 263 return (((uint64_t)1) << FieldSizeInBits) - 1; 264 } 265 static uint64_t maskAndShift(uint64_t Val, uint64_t Mask, uint8_t Shift) { 266 assert(Val <= Mask && "Value too large for field"); 267 return (Val & Mask) << Shift; 268 } 269 static uint64_t maskAndShift(uint64_t Val, const BitFieldInfo FieldInfo) { 270 return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]); 271 } 272 uint64_t getFieldValue(const BitFieldInfo FieldInfo) const { 273 return getMask(FieldInfo) & (RawData >> FieldInfo[1]); 274 } 275 276 void init(bool IsPointer, bool IsVector, uint16_t NumElements, 277 unsigned SizeInBits, unsigned AddressSpace) { 278 this->IsPointer = IsPointer; 279 this->IsVector = IsVector; 280 if (!IsVector) { 281 if (!IsPointer) 282 RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo); 283 else 284 RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) | 285 maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo); 286 } else { 287 assert(NumElements > 1 && "invalid number of vector elements"); 288 if (!IsPointer) 289 RawData = maskAndShift(NumElements, VectorElementsFieldInfo) | 290 maskAndShift(SizeInBits, VectorSizeFieldInfo); 291 else 292 RawData = 293 maskAndShift(NumElements, PointerVectorElementsFieldInfo) | 294 maskAndShift(SizeInBits, PointerVectorSizeFieldInfo) | 295 maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo); 296 } 297 } 298 299 uint64_t getUniqueRAWLLTData() const { 300 return ((uint64_t)RawData) << 2 | ((uint64_t)IsPointer) << 1 | 301 ((uint64_t)IsVector); 302 } 303 }; 304 305 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { 306 Ty.print(OS); 307 return OS; 308 } 309 310 template<> struct DenseMapInfo<LLT> { 311 static inline LLT getEmptyKey() { 312 LLT Invalid; 313 Invalid.IsPointer = true; 314 return Invalid; 315 } 316 static inline LLT getTombstoneKey() { 317 LLT Invalid; 318 Invalid.IsVector = true; 319 return Invalid; 320 } 321 static inline unsigned getHashValue(const LLT &Ty) { 322 uint64_t Val = Ty.getUniqueRAWLLTData(); 323 return DenseMapInfo<uint64_t>::getHashValue(Val); 324 } 325 static bool isEqual(const LLT &LHS, const LLT &RHS) { 326 return LHS == RHS; 327 } 328 }; 329 330 } 331 332 #endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H 333