| //== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- C++ -*-==// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// Implement a low-level type suitable for MachineInstr level instruction |
| /// selection. |
| /// |
| /// For a type attached to a MachineInstr, we only care about 2 details: total |
| /// size and the number of vector lanes (if any). Accordingly, there are 4 |
| /// possible valid type-kinds: |
| /// |
| /// * `sN` for scalars and aggregates |
| /// * `<N x sM>` for vectors, which must have at least 2 elements. |
| /// * `pN` for pointers |
| /// |
| /// Other information required for correct selection is expected to be carried |
| /// by the opcode, or non-type flags. For example the distinction between G_ADD |
| /// and G_FADD for int/float or fast-math flags. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H |
| #define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H |
| |
| #include <cassert> |
| #include "llvm/ADT/DenseMapInfo.h" |
| #include "llvm/CodeGen/MachineValueType.h" |
| |
| namespace llvm { |
| |
| class DataLayout; |
| class Type; |
| class raw_ostream; |
| |
| class LLT { |
| public: |
| enum TypeKind : uint16_t { |
| Invalid, |
| Scalar, |
| Pointer, |
| Vector, |
| }; |
| |
| /// Get a low-level scalar or aggregate "bag of bits". |
| static LLT scalar(unsigned SizeInBits) { |
| assert(SizeInBits > 0 && "invalid scalar size"); |
| return LLT{Scalar, 1, SizeInBits}; |
| } |
| |
| /// Get a low-level pointer in the given address space (defaulting to 0). |
| static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) { |
| return LLT{Pointer, AddressSpace, SizeInBits}; |
| } |
| |
| /// Get a low-level vector of some number of elements and element width. |
| /// \p NumElements must be at least 2. |
| static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) { |
| assert(NumElements > 1 && "invalid number of vector elements"); |
| return LLT{Vector, NumElements, ScalarSizeInBits}; |
| } |
| |
| /// Get a low-level vector of some number of elements and element type. |
| static LLT vector(uint16_t NumElements, LLT ScalarTy) { |
| assert(NumElements > 1 && "invalid number of vector elements"); |
| assert(ScalarTy.isScalar() && "invalid vector element type"); |
| return LLT{Vector, NumElements, ScalarTy.getSizeInBits()}; |
| } |
| |
| explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits) |
| : SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) { |
| assert((Kind != Vector || ElementsOrAddrSpace > 1) && |
| "invalid number of vector elements"); |
| } |
| |
| explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {} |
| |
| explicit LLT(MVT VT); |
| |
| bool isValid() const { return Kind != Invalid; } |
| |
| bool isScalar() const { return Kind == Scalar; } |
| |
| bool isPointer() const { return Kind == Pointer; } |
| |
| bool isVector() const { return Kind == Vector; } |
| |
| /// Returns the number of elements in a vector LLT. Must only be called on |
| /// vector types. |
| uint16_t getNumElements() const { |
| assert(isVector() && "cannot get number of elements on scalar/aggregate"); |
| return ElementsOrAddrSpace; |
| } |
| |
| /// Returns the total size of the type. Must only be called on sized types. |
| unsigned getSizeInBits() const { |
| if (isPointer() || isScalar()) |
| return SizeInBits; |
| return SizeInBits * ElementsOrAddrSpace; |
| } |
| |
| unsigned getScalarSizeInBits() const { |
| return SizeInBits; |
| } |
| |
| unsigned getAddressSpace() const { |
| assert(isPointer() && "cannot get address space of non-pointer type"); |
| return ElementsOrAddrSpace; |
| } |
| |
| /// Returns the vector's element type. Only valid for vector types. |
| LLT getElementType() const { |
| assert(isVector() && "cannot get element type of scalar/aggregate"); |
| return scalar(SizeInBits); |
| } |
| |
| /// Get a low-level type with half the size of the original, by halving the |
| /// size of the scalar type involved. For example `s32` will become `s16`, |
| /// `<2 x s32>` will become `<2 x s16>`. |
| LLT halfScalarSize() const { |
| assert(!isPointer() && getScalarSizeInBits() > 1 && |
| getScalarSizeInBits() % 2 == 0 && "cannot half size of this type"); |
| return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2}; |
| } |
| |
| /// Get a low-level type with twice the size of the original, by doubling the |
| /// size of the scalar type involved. For example `s32` will become `s64`, |
| /// `<2 x s32>` will become `<2 x s64>`. |
| LLT doubleScalarSize() const { |
| assert(!isPointer() && "cannot change size of this type"); |
| return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2}; |
| } |
| |
| /// Get a low-level type with half the size of the original, by halving the |
| /// number of vector elements of the scalar type involved. The source must be |
| /// a vector type with an even number of elements. For example `<4 x s32>` |
| /// will become `<2 x s32>`, `<2 x s32>` will become `s32`. |
| LLT halfElements() const { |
| assert(isVector() && ElementsOrAddrSpace % 2 == 0 && |
| "cannot half odd vector"); |
| if (ElementsOrAddrSpace == 2) |
| return scalar(SizeInBits); |
| |
| return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2), |
| SizeInBits}; |
| } |
| |
| /// Get a low-level type with twice the size of the original, by doubling the |
| /// number of vector elements of the scalar type involved. The source must be |
| /// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling |
| /// the number of elements in sN produces <2 x sN>. |
| LLT doubleElements() const { |
| assert(!isPointer() && "cannot double elements in pointer"); |
| return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2), |
| SizeInBits}; |
| } |
| |
| void print(raw_ostream &OS) const; |
| |
| bool operator==(const LLT &RHS) const { |
| return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits && |
| ElementsOrAddrSpace == RHS.ElementsOrAddrSpace; |
| } |
| |
| bool operator!=(const LLT &RHS) const { return !(*this == RHS); } |
| |
| friend struct DenseMapInfo<LLT>; |
| private: |
| unsigned SizeInBits; |
| uint16_t ElementsOrAddrSpace; |
| TypeKind Kind; |
| }; |
| |
| inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) { |
| Ty.print(OS); |
| return OS; |
| } |
| |
| template<> struct DenseMapInfo<LLT> { |
| static inline LLT getEmptyKey() { |
| return LLT{LLT::Invalid, 0, -1u}; |
| } |
| static inline LLT getTombstoneKey() { |
| return LLT{LLT::Invalid, 0, -2u}; |
| } |
| static inline unsigned getHashValue(const LLT &Ty) { |
| uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) | |
| ((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind; |
| return DenseMapInfo<uint64_t>::getHashValue(Val); |
| } |
| static bool isEqual(const LLT &LHS, const LLT &RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| } |
| |
| #endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H |