blob: 02df4d806f13bfd163cf85f16b3d88925db56359 [file] [log] [blame]
//== 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