#ifndef LLVM_IR_DERIVEDTYPES_H
#define LLVM_IR_DERIVEDTYPES_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/TypeSize.h"
#include <cassert>
#include <cstdint>
namespace llvm {
class Value;
class APInt;
class LLVMContext;
class IntegerType : public Type {
friend class LLVMContextImpl;
protected:
explicit IntegerType(LLVMContext &C, unsigned NumBits) : Type(C, IntegerTyID){
setSubclassData(NumBits);
}
public:
enum {
MIN_INT_BITS = 1, MAX_INT_BITS = (1<<23) };
static IntegerType *get(LLVMContext &C, unsigned NumBits);
IntegerType *getExtendedType() const {
return Type::getIntNTy(getContext(), 2 * getScalarSizeInBits());
}
unsigned getBitWidth() const { return getSubclassData(); }
uint64_t getBitMask() const {
return ~uint64_t(0UL) >> (64-getBitWidth());
}
uint64_t getSignBit() const {
return 1ULL << (getBitWidth()-1);
}
APInt getMask() const;
static bool classof(const Type *T) {
return T->getTypeID() == IntegerTyID;
}
};
unsigned Type::getIntegerBitWidth() const {
return cast<IntegerType>(this)->getBitWidth();
}
class FunctionType : public Type {
FunctionType(Type *Result, ArrayRef<Type*> Params, bool IsVarArgs);
public:
FunctionType(const FunctionType &) = delete;
FunctionType &operator=(const FunctionType &) = delete;
static FunctionType *get(Type *Result,
ArrayRef<Type*> Params, bool isVarArg);
static FunctionType *get(Type *Result, bool isVarArg);
static bool isValidReturnType(Type *RetTy);
static bool isValidArgumentType(Type *ArgTy);
bool isVarArg() const { return getSubclassData()!=0; }
Type *getReturnType() const { return ContainedTys[0]; }
using param_iterator = Type::subtype_iterator;
param_iterator param_begin() const { return ContainedTys + 1; }
param_iterator param_end() const { return &ContainedTys[NumContainedTys]; }
ArrayRef<Type *> params() const {
return makeArrayRef(param_begin(), param_end());
}
Type *getParamType(unsigned i) const { return ContainedTys[i+1]; }
unsigned getNumParams() const { return NumContainedTys - 1; }
static bool classof(const Type *T) {
return T->getTypeID() == FunctionTyID;
}
};
static_assert(alignof(FunctionType) >= alignof(Type *),
"Alignment sufficient for objects appended to FunctionType");
bool Type::isFunctionVarArg() const {
return cast<FunctionType>(this)->isVarArg();
}
Type *Type::getFunctionParamType(unsigned i) const {
return cast<FunctionType>(this)->getParamType(i);
}
unsigned Type::getFunctionNumParams() const {
return cast<FunctionType>(this)->getNumParams();
}
class FunctionCallee {
public:
template <typename T, typename U = decltype(&T::getFunctionType)>
FunctionCallee(T *Fn)
: FnTy(Fn ? Fn->getFunctionType() : nullptr), Callee(Fn) {}
FunctionCallee(FunctionType *FnTy, Value *Callee)
: FnTy(FnTy), Callee(Callee) {
assert((FnTy == nullptr) == (Callee == nullptr));
}
FunctionCallee(std::nullptr_t) {}
FunctionCallee() = default;
FunctionType *getFunctionType() { return FnTy; }
Value *getCallee() { return Callee; }
explicit operator bool() { return Callee; }
private:
FunctionType *FnTy = nullptr;
Value *Callee = nullptr;
};
class StructType : public Type {
StructType(LLVMContext &C) : Type(C, StructTyID) {}
enum {
SCDB_HasBody = 1,
SCDB_Packed = 2,
SCDB_IsLiteral = 4,
SCDB_IsSized = 8
};
void *SymbolTableEntry = nullptr;
public:
StructType(const StructType &) = delete;
StructType &operator=(const StructType &) = delete;
static StructType *create(LLVMContext &Context, StringRef Name);
static StructType *create(LLVMContext &Context);
static StructType *create(ArrayRef<Type *> Elements, StringRef Name,
bool isPacked = false);
static StructType *create(ArrayRef<Type *> Elements);
static StructType *create(LLVMContext &Context, ArrayRef<Type *> Elements,
StringRef Name, bool isPacked = false);
static StructType *create(LLVMContext &Context, ArrayRef<Type *> Elements);
template <class... Tys>
static std::enable_if_t<are_base_of<Type, Tys...>::value, StructType *>
create(StringRef Name, Type *elt1, Tys *... elts) {
assert(elt1 && "Cannot create a struct type with no elements with this");
return create(ArrayRef<Type *>({elt1, elts...}), Name);
}
static StructType *get(LLVMContext &Context, ArrayRef<Type*> Elements,
bool isPacked = false);
static StructType *get(LLVMContext &Context, bool isPacked = false);
template <class... Tys>
static std::enable_if_t<are_base_of<Type, Tys...>::value, StructType *>
get(Type *elt1, Tys *... elts) {
assert(elt1 && "Cannot create a struct type with no elements with this");
LLVMContext &Ctx = elt1->getContext();
return StructType::get(Ctx, ArrayRef<Type *>({elt1, elts...}));
}
static StructType *getTypeByName(LLVMContext &C, StringRef Name);
bool isPacked() const { return (getSubclassData() & SCDB_Packed) != 0; }
bool isLiteral() const { return (getSubclassData() & SCDB_IsLiteral) != 0; }
bool isOpaque() const { return (getSubclassData() & SCDB_HasBody) == 0; }
bool isSized(SmallPtrSetImpl<Type *> *Visited = nullptr) const;
bool containsScalableVectorType() const;
bool hasName() const { return SymbolTableEntry != nullptr; }
StringRef getName() const;
void setName(StringRef Name);
void setBody(ArrayRef<Type*> Elements, bool isPacked = false);
template <typename... Tys>
std::enable_if_t<are_base_of<Type, Tys...>::value, void>
setBody(Type *elt1, Tys *... elts) {
assert(elt1 && "Cannot create a struct type with no elements with this");
setBody(ArrayRef<Type *>({elt1, elts...}));
}
static bool isValidElementType(Type *ElemTy);
using element_iterator = Type::subtype_iterator;
element_iterator element_begin() const { return ContainedTys; }
element_iterator element_end() const { return &ContainedTys[NumContainedTys];}
ArrayRef<Type *> elements() const {
return makeArrayRef(element_begin(), element_end());
}
bool isLayoutIdentical(StructType *Other) const;
unsigned getNumElements() const { return NumContainedTys; }
Type *getElementType(unsigned N) const {
assert(N < NumContainedTys && "Element number out of range!");
return ContainedTys[N];
}
Type *getTypeAtIndex(const Value *V) const;
Type *getTypeAtIndex(unsigned N) const { return getElementType(N); }
bool indexValid(const Value *V) const;
bool indexValid(unsigned Idx) const { return Idx < getNumElements(); }
static bool classof(const Type *T) {
return T->getTypeID() == StructTyID;
}
};
StringRef Type::getStructName() const {
return cast<StructType>(this)->getName();
}
unsigned Type::getStructNumElements() const {
return cast<StructType>(this)->getNumElements();
}
Type *Type::getStructElementType(unsigned N) const {
return cast<StructType>(this)->getElementType(N);
}
class ArrayType : public Type {
Type *ContainedType;
uint64_t NumElements;
ArrayType(Type *ElType, uint64_t NumEl);
public:
ArrayType(const ArrayType &) = delete;
ArrayType &operator=(const ArrayType &) = delete;
uint64_t getNumElements() const { return NumElements; }
Type *getElementType() const { return ContainedType; }
static ArrayType *get(Type *ElementType, uint64_t NumElements);
static bool isValidElementType(Type *ElemTy);
static bool classof(const Type *T) {
return T->getTypeID() == ArrayTyID;
}
};
uint64_t Type::getArrayNumElements() const {
return cast<ArrayType>(this)->getNumElements();
}
class VectorType : public Type {
Type *ContainedType;
protected:
const unsigned ElementQuantity;
VectorType(Type *ElType, unsigned EQ, Type::TypeID TID);
public:
VectorType(const VectorType &) = delete;
VectorType &operator=(const VectorType &) = delete;
Type *getElementType() const { return ContainedType; }
static VectorType *get(Type *ElementType, ElementCount EC);
static VectorType *get(Type *ElementType, unsigned NumElements,
bool Scalable) {
return VectorType::get(ElementType,
ElementCount::get(NumElements, Scalable));
}
static VectorType *get(Type *ElementType, const VectorType *Other) {
return VectorType::get(ElementType, Other->getElementCount());
}
static VectorType *getInteger(VectorType *VTy) {
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
assert(EltBits && "Element size must be of a non-zero size");
Type *EltTy = IntegerType::get(VTy->getContext(), EltBits);
return VectorType::get(EltTy, VTy->getElementCount());
}
static VectorType *getExtendedElementVectorType(VectorType *VTy) {
assert(VTy->isIntOrIntVectorTy() && "VTy expected to be a vector of ints.");
auto *EltTy = cast<IntegerType>(VTy->getElementType());
return VectorType::get(EltTy->getExtendedType(), VTy->getElementCount());
}
static VectorType *getTruncatedElementVectorType(VectorType *VTy) {
Type *EltTy;
if (VTy->getElementType()->isFloatingPointTy()) {
switch(VTy->getElementType()->getTypeID()) {
case DoubleTyID:
EltTy = Type::getFloatTy(VTy->getContext());
break;
case FloatTyID:
EltTy = Type::getHalfTy(VTy->getContext());
break;
default:
llvm_unreachable("Cannot create narrower fp vector element type");
}
} else {
unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
assert((EltBits & 1) == 0 &&
"Cannot truncate vector element with odd bit-width");
EltTy = IntegerType::get(VTy->getContext(), EltBits / 2);
}
return VectorType::get(EltTy, VTy->getElementCount());
}
static VectorType *getSubdividedVectorType(VectorType *VTy, int NumSubdivs) {
for (int i = 0; i < NumSubdivs; ++i) {
VTy = VectorType::getDoubleElementsVectorType(VTy);
VTy = VectorType::getTruncatedElementVectorType(VTy);
}
return VTy;
}
static VectorType *getHalfElementsVectorType(VectorType *VTy) {
auto EltCnt = VTy->getElementCount();
assert(EltCnt.isKnownEven() &&
"Cannot halve vector with odd number of elements.");
return VectorType::get(VTy->getElementType(),
EltCnt.divideCoefficientBy(2));
}
static VectorType *getDoubleElementsVectorType(VectorType *VTy) {
auto EltCnt = VTy->getElementCount();
assert((EltCnt.getKnownMinValue() * 2ull) <= UINT_MAX &&
"Too many elements in vector");
return VectorType::get(VTy->getElementType(), EltCnt * 2);
}
static bool isValidElementType(Type *ElemTy);
inline ElementCount getElementCount() const;
static bool classof(const Type *T) {
return T->getTypeID() == FixedVectorTyID ||
T->getTypeID() == ScalableVectorTyID;
}
};
class FixedVectorType : public VectorType {
protected:
FixedVectorType(Type *ElTy, unsigned NumElts)
: VectorType(ElTy, NumElts, FixedVectorTyID) {}
public:
static FixedVectorType *get(Type *ElementType, unsigned NumElts);
static FixedVectorType *get(Type *ElementType, const FixedVectorType *FVTy) {
return get(ElementType, FVTy->getNumElements());
}
static FixedVectorType *getInteger(FixedVectorType *VTy) {
return cast<FixedVectorType>(VectorType::getInteger(VTy));
}
static FixedVectorType *getExtendedElementVectorType(FixedVectorType *VTy) {
return cast<FixedVectorType>(VectorType::getExtendedElementVectorType(VTy));
}
static FixedVectorType *getTruncatedElementVectorType(FixedVectorType *VTy) {
return cast<FixedVectorType>(
VectorType::getTruncatedElementVectorType(VTy));
}
static FixedVectorType *getSubdividedVectorType(FixedVectorType *VTy,
int NumSubdivs) {
return cast<FixedVectorType>(
VectorType::getSubdividedVectorType(VTy, NumSubdivs));
}
static FixedVectorType *getHalfElementsVectorType(FixedVectorType *VTy) {
return cast<FixedVectorType>(VectorType::getHalfElementsVectorType(VTy));
}
static FixedVectorType *getDoubleElementsVectorType(FixedVectorType *VTy) {
return cast<FixedVectorType>(VectorType::getDoubleElementsVectorType(VTy));
}
static bool classof(const Type *T) {
return T->getTypeID() == FixedVectorTyID;
}
unsigned getNumElements() const { return ElementQuantity; }
};
class ScalableVectorType : public VectorType {
protected:
ScalableVectorType(Type *ElTy, unsigned MinNumElts)
: VectorType(ElTy, MinNumElts, ScalableVectorTyID) {}
public:
static ScalableVectorType *get(Type *ElementType, unsigned MinNumElts);
static ScalableVectorType *get(Type *ElementType,
const ScalableVectorType *SVTy) {
return get(ElementType, SVTy->getMinNumElements());
}
static ScalableVectorType *getInteger(ScalableVectorType *VTy) {
return cast<ScalableVectorType>(VectorType::getInteger(VTy));
}
static ScalableVectorType *
getExtendedElementVectorType(ScalableVectorType *VTy) {
return cast<ScalableVectorType>(
VectorType::getExtendedElementVectorType(VTy));
}
static ScalableVectorType *
getTruncatedElementVectorType(ScalableVectorType *VTy) {
return cast<ScalableVectorType>(
VectorType::getTruncatedElementVectorType(VTy));
}
static ScalableVectorType *getSubdividedVectorType(ScalableVectorType *VTy,
int NumSubdivs) {
return cast<ScalableVectorType>(
VectorType::getSubdividedVectorType(VTy, NumSubdivs));
}
static ScalableVectorType *
getHalfElementsVectorType(ScalableVectorType *VTy) {
return cast<ScalableVectorType>(VectorType::getHalfElementsVectorType(VTy));
}
static ScalableVectorType *
getDoubleElementsVectorType(ScalableVectorType *VTy) {
return cast<ScalableVectorType>(
VectorType::getDoubleElementsVectorType(VTy));
}
uint64_t getMinNumElements() const { return ElementQuantity; }
static bool classof(const Type *T) {
return T->getTypeID() == ScalableVectorTyID;
}
};
inline ElementCount VectorType::getElementCount() const {
return ElementCount::get(ElementQuantity, isa<ScalableVectorType>(this));
}
class PointerType : public Type {
explicit PointerType(Type *ElType, unsigned AddrSpace);
explicit PointerType(LLVMContext &C, unsigned AddrSpace);
Type *PointeeTy;
public:
PointerType(const PointerType &) = delete;
PointerType &operator=(const PointerType &) = delete;
static PointerType *get(Type *ElementType, unsigned AddressSpace);
static PointerType *get(LLVMContext &C, unsigned AddressSpace);
static PointerType *getUnqual(Type *ElementType) {
return PointerType::get(ElementType, 0);
}
static PointerType *getUnqual(LLVMContext &C) {
return PointerType::get(C, 0);
}
static PointerType *getWithSamePointeeType(PointerType *PT,
unsigned AddressSpace) {
if (PT->isOpaque())
return get(PT->getContext(), AddressSpace);
return get(PT->PointeeTy, AddressSpace);
}
bool isOpaque() const { return !PointeeTy; }
static bool isValidElementType(Type *ElemTy);
static bool isLoadableOrStorableType(Type *ElemTy);
inline unsigned getAddressSpace() const { return getSubclassData(); }
bool isOpaqueOrPointeeTypeMatches(Type *Ty) {
return isOpaque() || PointeeTy == Ty;
}
bool hasSameElementTypeAs(PointerType *Other) {
return PointeeTy == Other->PointeeTy;
}
static bool classof(const Type *T) {
return T->getTypeID() == PointerTyID;
}
};
Type *Type::getExtendedType() const {
assert(
isIntOrIntVectorTy() &&
"Original type expected to be a vector of integers or a scalar integer.");
if (auto *VTy = dyn_cast<VectorType>(this))
return VectorType::getExtendedElementVectorType(
const_cast<VectorType *>(VTy));
return cast<IntegerType>(this)->getExtendedType();
}
Type *Type::getWithNewType(Type *EltTy) const {
if (auto *VTy = dyn_cast<VectorType>(this))
return VectorType::get(EltTy, VTy->getElementCount());
return EltTy;
}
Type *Type::getWithNewBitWidth(unsigned NewBitWidth) const {
assert(
isIntOrIntVectorTy() &&
"Original type expected to be a vector of integers or a scalar integer.");
return getWithNewType(getIntNTy(getContext(), NewBitWidth));
}
unsigned Type::getPointerAddressSpace() const {
return cast<PointerType>(getScalarType())->getAddressSpace();
}
}
#endif