10#include "TypeDetail.h"
20#include "llvm/ADT/APFloat.h"
21#include "llvm/ADT/APInt.h"
22#include "llvm/ADT/Sequence.h"
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/CheckedArithmetic.h"
34#define GET_TYPEDEF_CLASSES
35#include "mlir/IR/BuiltinTypes.cpp.inc"
38#include "mlir/IR/BuiltinTypeConstraints.cpp.inc"
45void BuiltinDialect::registerTypes() {
47#define GET_TYPEDEF_LIST
48#include "mlir/IR/BuiltinTypes.cpp.inc"
60 return emitError() <<
"invalid element type for complex";
64size_t ComplexType::getDenseElementBitSize()
const {
66 return llvm::alignTo<8>(elemTy.getDenseElementBitSize()) * 2;
71 size_t singleElementBytes =
72 llvm::alignTo<8>(elemTy.getDenseElementBitSize()) / 8;
74 elemTy.convertToAttribute(rawData.take_front(singleElementBytes));
76 elemTy.convertToAttribute(rawData.take_back(singleElementBytes));
81ComplexType::convertFromAttribute(
Attribute attr,
83 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
84 if (!arrayAttr || arrayAttr.size() != 2)
88 if (
failed(elemTy.convertFromAttribute(arrayAttr[0], realData)))
90 if (
failed(elemTy.convertFromAttribute(arrayAttr[1], imagData)))
104 SignednessSemantics signedness) {
105 if (width > IntegerType::kMaxWidth) {
106 return emitError() <<
"integer bitwidth is limited to "
107 << IntegerType::kMaxWidth <<
" bits";
112unsigned IntegerType::getWidth()
const {
return getImpl()->width; }
114IntegerType::SignednessSemantics IntegerType::getSignedness()
const {
115 return getImpl()->signedness;
118IntegerType IntegerType::scaleElementBitwidth(
unsigned scale) {
120 return IntegerType();
121 return IntegerType::get(
getContext(), scale * getWidth(), getSignedness());
124size_t IntegerType::getDenseElementBitSize()
const {
130 APInt value = detail::readBits(rawData.data(), 0, getWidth());
131 return IntegerAttr::get(*
this, value);
135 size_t byteSize = llvm::divideCeil(apInt.getBitWidth(), CHAR_BIT);
136 size_t bitPos =
result.size() * CHAR_BIT;
142IntegerType::convertFromAttribute(
Attribute attr,
144 auto intAttr = dyn_cast<IntegerAttr>(attr);
145 if (!intAttr || intAttr.getType() != *
this)
155size_t IndexType::getDenseElementBitSize()
const {
156 return kInternalStorageBitWidth;
161 detail::readBits(rawData.data(), 0, kInternalStorageBitWidth);
162 return IntegerAttr::get(*
this, value);
166IndexType::convertFromAttribute(
Attribute attr,
168 auto intAttr = dyn_cast<IntegerAttr>(attr);
169 if (!intAttr || intAttr.getType() != *
this)
180#define FLOAT_TYPE_SEMANTICS(TYPE, SEM) \
181 const llvm::fltSemantics &TYPE::getFloatSemantics() const { \
182 return APFloat::SEM(); \
203#undef FLOAT_TYPE_SEMANTICS
205FloatType Float16Type::scaleElementBitwidth(
unsigned scale)
const {
213FloatType BFloat16Type::scaleElementBitwidth(
unsigned scale)
const {
221FloatType Float32Type::scaleElementBitwidth(
unsigned scale)
const {
231unsigned FunctionType::getNumInputs()
const {
return getImpl()->numInputs; }
234 return getImpl()->getInputs();
237unsigned FunctionType::getNumResults()
const {
return getImpl()->numResults; }
240 return getImpl()->getResults();
249FunctionType FunctionType::getWithArgsAndResults(
256 insertTypesInto(getResults(), resultIndices, resultTypes, resultStorage);
257 return clone(newArgTypes, newResultTypes);
262FunctionType::getWithoutArgsAndResults(
const BitVector &argIndices,
263 const BitVector &resultIndices) {
268 return clone(newArgTypes, newResultTypes);
275unsigned GraphType::getNumInputs()
const {
return getImpl()->numInputs; }
277ArrayRef<Type> GraphType::getInputs()
const {
return getImpl()->getInputs(); }
279unsigned GraphType::getNumResults()
const {
return getImpl()->numResults; }
281ArrayRef<Type> GraphType::getResults()
const {
return getImpl()->getResults(); }
297 insertTypesInto(getResults(), resultIndices, resultTypes, resultStorage);
298 return clone(newArgTypes, newResultTypes);
302GraphType GraphType::getWithoutArgsAndResults(
const BitVector &argIndices,
303 const BitVector &resultIndices) {
308 return clone(newArgTypes, newResultTypes);
316 StringAttr dialect, StringRef typeData) {
318 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
325 <<
"`!" << dialect <<
"<\"" << typeData <<
"\">"
326 <<
"` type created with unregistered dialect. If this is "
327 "intended, please call allowUnregisteredDialects() on the "
328 "MLIRContext, or use -allow-unregistered-dialect with "
329 "the MLIR opt tool used";
339bool VectorType::isValidElementType(
Type t) {
340 return isValidVectorTypeElementType(t);
346 if (!isValidElementType(elementType))
348 <<
"vector elements must be int/index/float type but got "
351 if (any_of(shape, [](int64_t i) {
return i <= 0; }))
353 <<
"vector types must have positive constant sizes but got "
356 if (scalableDims.size() != shape.size())
357 return emitError() <<
"number of dims must match, got "
358 << scalableDims.size() <<
" and " << shape.size();
363VectorType VectorType::scaleElementBitwidth(
unsigned scale) {
367 if (
auto scaledEt = et.scaleElementBitwidth(scale))
368 return VectorType::get(
getShape(), scaledEt, getScalableDims());
370 if (
auto scaledEt = et.scaleElementBitwidth(scale))
371 return VectorType::get(
getShape(), scaledEt, getScalableDims());
376 Type elementType)
const {
377 return VectorType::get(shape.value_or(
getShape()), elementType,
387 .Case<RankedTensorType, UnrankedTensorType>(
388 [](
auto type) {
return type.getElementType(); });
392 return !llvm::isa<UnrankedTensorType>(*
this);
396 return llvm::cast<RankedTensorType>(*this).getShape();
400 Type elementType)
const {
401 if (llvm::dyn_cast<UnrankedTensorType>(*
this)) {
403 return RankedTensorType::get(*
shape, elementType);
404 return UnrankedTensorType::get(elementType);
407 auto rankedTy = llvm::cast<RankedTensorType>(*
this);
409 return RankedTensorType::get(rankedTy.getShape(), elementType,
410 rankedTy.getEncoding());
411 return RankedTensorType::get(
shape.value_or(rankedTy.getShape()), elementType,
412 rankedTy.getEncoding());
416 Type elementType)
const {
417 return ::llvm::cast<RankedTensorType>(
cloneWith(
shape, elementType));
429 return emitError() <<
"invalid tensor element type: " << elementType;
438 return llvm::isa<ComplexType, FloatType, IntegerType, OpaqueType, VectorType,
440 !llvm::isa<BuiltinDialect>(type.
getDialect());
452 if (s < 0 && ShapedType::isStatic(s))
453 return emitError() <<
"invalid tensor dimension size";
454 if (
auto v = llvm::dyn_cast_or_null<VerifiableTensorEncoding>(encoding))
477 [](
auto type) {
return type.getElementType(); });
481 return !llvm::isa<UnrankedMemRefType>(*
this);
485 return llvm::cast<MemRefType>(*this).getShape();
489 Type elementType)
const {
490 if (llvm::dyn_cast<UnrankedMemRefType>(*
this)) {
505FailureOr<PtrLikeTypeInterface>
507 std::optional<Type> elementType)
const {
509 if (llvm::dyn_cast<UnrankedMemRefType>(*
this))
510 return cast<PtrLikeTypeInterface>(
511 UnrankedMemRefType::get(eTy, memorySpace));
516 return cast<PtrLikeTypeInterface>(
static_cast<MemRefType
>(builder));
520 Type elementType)
const {
529 if (
auto rankedMemRefTy = llvm::dyn_cast<MemRefType>(*
this))
530 return rankedMemRefTy.getMemorySpace();
531 return llvm::cast<UnrankedMemRefType>(*this).getMemorySpace();
535 if (
auto rankedMemRefTy = llvm::dyn_cast<MemRefType>(*
this))
536 return rankedMemRefTy.getMemorySpaceAsInt();
537 return llvm::cast<UnrankedMemRefType>(*this).getMemorySpaceAsInt();
544std::optional<llvm::SmallDenseSet<unsigned>>
548 size_t originalRank = originalShape.size(), reducedRank = reducedShape.size();
549 llvm::SmallDenseSet<unsigned> unusedDims;
550 unsigned reducedIdx = 0;
551 for (
unsigned originalIdx = 0; originalIdx < originalRank; ++originalIdx) {
553 int64_t origSize = originalShape[originalIdx];
555 if (matchDynamic && reducedIdx < reducedRank && origSize != 1 &&
556 (ShapedType::isDynamic(reducedShape[reducedIdx]) ||
557 ShapedType::isDynamic(origSize))) {
561 if (reducedIdx < reducedRank && origSize == reducedShape[reducedIdx]) {
566 unusedDims.insert(originalIdx);
573 if (reducedIdx != reducedRank)
580 ShapedType candidateReducedType) {
581 if (originalType == candidateReducedType)
584 ShapedType originalShapedType = llvm::cast<ShapedType>(originalType);
585 ShapedType candidateReducedShapedType =
586 llvm::cast<ShapedType>(candidateReducedType);
591 candidateReducedShapedType.getShape();
592 unsigned originalRank = originalShape.size(),
593 candidateReducedRank = candidateReducedShape.size();
594 if (candidateReducedRank > originalRank)
597 auto optionalUnusedDimsMask =
601 if (!optionalUnusedDimsMask)
604 if (originalShapedType.getElementType() !=
605 candidateReducedShapedType.getElementType())
613 if (memorySpace == 0)
616 return IntegerAttr::get(IntegerType::get(ctx, 64), memorySpace);
620 IntegerAttr intMemorySpace = llvm::dyn_cast_or_null<IntegerAttr>(memorySpace);
621 if (intMemorySpace && intMemorySpace.getValue() == 0)
631 assert(llvm::isa<IntegerAttr>(memorySpace) &&
632 "Using `getMemorySpaceInteger` with non-Integer attribute");
634 return static_cast<unsigned>(llvm::cast<IntegerAttr>(memorySpace).getInt());
637unsigned MemRefType::getMemorySpaceAsInt()
const {
642 MemRefLayoutAttrInterface layout,
656MemRefType MemRefType::getChecked(
658 Type elementType, MemRefLayoutAttrInterface layout,
Attribute memorySpace) {
669 elementType, layout, memorySpace);
681 auto layout = AffineMapAttr::get(map);
701 auto layout = AffineMapAttr::get(map);
707 elementType, layout, memorySpace);
711 AffineMap map,
unsigned memorySpaceInd) {
719 auto layout = AffineMapAttr::get(map);
732 unsigned memorySpaceInd) {
740 auto layout = AffineMapAttr::get(map);
747 elementType, layout, memorySpace);
752 MemRefLayoutAttrInterface layout,
755 return emitError() <<
"invalid memref element type";
758 for (int64_t s :
shape)
759 if (s < 0 && ShapedType::isStatic(s))
760 return emitError() <<
"invalid memref size";
762 assert(layout &&
"missing layout specification");
769bool MemRefType::areTrailingDimsContiguous(int64_t n) {
770 assert(n <= getRank() &&
771 "number of dimensions to check must not exceed rank");
772 return n <= getNumContiguousTrailingDims();
775int64_t MemRefType::getNumContiguousTrailingDims() {
776 const int64_t n = getRank();
779 if (getLayout().isIdentity())
797 int64_t dimProduct = 1;
798 for (int64_t i = n - 1; i >= 0; --i) {
801 if (strides[i] != dimProduct)
803 if (
shape[i] == ShapedType::kDynamic)
805 dimProduct *=
shape[i];
811MemRefType MemRefType::canonicalizeStridedLayout() {
812 AffineMap m = getLayout().getAffineMap();
824 if (
auto cst = llvm::dyn_cast<AffineConstantExpr>(m.
getResult(0)))
825 if (cst.getValue() == 0)
840 auto simplifiedLayoutExpr =
842 if (expr != simplifiedLayoutExpr)
845 simplifiedLayoutExpr)));
850 int64_t &offset)
const {
851 return getLayout().getStridesAndOffset(
getShape(), strides, offset);
854std::pair<SmallVector<int64_t>, int64_t>
855MemRefType::getStridesAndOffset()
const {
860 assert(succeeded(status) &&
"Invalid use of check-free getStridesAndOffset");
861 return {strides, offset};
864bool MemRefType::isStrided() {
868 return succeeded(res);
871bool MemRefType::isLastDimUnitStride() {
875 return succeeded(successStrides) && (strides.empty() || strides.back() == 1);
882unsigned UnrankedMemRefType::getMemorySpaceAsInt()
const {
890 return emitError() <<
"invalid memref element type";
900ArrayRef<Type> TupleType::getTypes()
const {
return getImpl()->getTypes(); }
907 for (
Type type : getTypes()) {
908 if (
auto nestedTuple = llvm::dyn_cast<TupleType>(type))
909 nestedTuple.getFlattenedTypes(types);
911 types.push_back(type);
916size_t TupleType::size()
const {
return getImpl()->size(); }
929 assert(!exprs.empty() &&
"expected exprs");
931 assert(!maps.empty() &&
"Expected one non-empty map");
932 unsigned numDims = maps[0].getNumDims(), nSymbols = maps[0].getNumSymbols();
935 bool dynamicPoisonBit =
false;
937 for (
auto en : llvm::zip(llvm::reverse(exprs), llvm::reverse(sizes))) {
938 int64_t size = std::get<1>(en);
943 expr = expr ? expr + dimExpr * stride : dimExpr * stride;
945 auto result = llvm::checkedMul(runningSize, size);
948 dynamicPoisonBit =
true;
953 dynamicPoisonBit =
true;
962 exprs.reserve(sizes.size());
963 for (
auto dim : llvm::seq<unsigned>(0, sizes.size()))
static LogicalResult getStridesAndOffset(AffineMap m, ArrayRef< int64_t > shape, SmallVectorImpl< AffineExpr > &strides, AffineExpr &offset)
A stride specification is a list of integer values that are either static or dynamic (encoded with Sh...
static void writeAPIntToVector(APInt apInt, SmallVectorImpl< char > &result)
static LogicalResult checkTensorElementType(function_ref< InFlightDiagnostic()> emitError, Type elementType)
#define FLOAT_TYPE_SEMANTICS(TYPE, SEM)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumSymbols() const
unsigned getNumDims() const
unsigned getNumResults() const
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr > > exprsList, MLIRContext *context)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
AffineExpr getResult(unsigned idx) const
bool isIdentity() const
Returns true if this affine map is an identity affine map.
Attributes are known-constant values of operations.
This class provides a shared interface for ranked and unranked memref types.
ArrayRef< int64_t > getShape() const
Returns the shape of this memref type.
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a memref.
FailureOr< PtrLikeTypeInterface > clonePtrWith(Attribute memorySpace, std::optional< Type > elementType) const
Clone this type with the given memory space and element type.
Attribute getMemorySpace() const
Returns the memory space in which data referred to by this memref resides.
unsigned getMemorySpaceAsInt() const
[deprecated] Returns the memory space in old raw integer representation.
BaseMemRefType cloneWith(std::optional< ArrayRef< int64_t > > shape, Type elementType) const
Clone this type with the given shape and element type.
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
Type getElementType() const
Returns the element type of this memref type.
MemRefType clone(ArrayRef< int64_t > shape, Type elementType) const
Return a clone of this type with the given new shape and element type.
static bool isValidNamespace(StringRef str)
Utility function that returns if the given string is a valid dialect namespace.
This class represents a diagnostic that is inflight and set to be reported.
MLIRContext is the top-level object for a collection of MLIR operations.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
bool allowsUnregisteredDialects()
Return true if we allow to create operation for unregistered dialects.
This is a builder type that keeps local references to arguments.
Builder & setShape(ArrayRef< int64_t > newShape)
Builder & setMemorySpace(Attribute newMemorySpace)
Builder & setElementType(Type newElementType)
Builder & setLayout(MemRefLayoutAttrInterface newLayout)
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
TensorType cloneWith(std::optional< ArrayRef< int64_t > > shape, Type elementType) const
Clone this type with the given shape and element type.
static bool isValidElementType(Type type)
Return true if the specified element type is ok in a tensor.
ArrayRef< int64_t > getShape() const
Returns the shape of this tensor type.
bool hasRank() const
Returns if this type is ranked, i.e. it has a known number of dimensions.
RankedTensorType clone(ArrayRef< int64_t > shape, Type elementType) const
Return a clone of this type with the given new shape and element type.
Type getElementType() const
Returns the element type of this tensor type.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Dialect & getDialect() const
Get the dialect this type is registered to.
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Attribute wrapIntegerMemorySpace(unsigned memorySpace, MLIRContext *ctx)
Wraps deprecated integer memory space to the new Attribute form.
unsigned getMemorySpaceAsInt(Attribute memorySpace)
[deprecated] Returns the memory space in old raw integer representation.
Attribute skipDefaultMemorySpace(Attribute memorySpace)
Replaces default memorySpace (integer == 0) with empty Attribute.
void writeBits(char *rawData, size_t bitPos, llvm::APInt value)
Write value to byte-aligned position bitPos in rawData.
Include the generated interface declarations.
SliceVerificationResult
Enum that captures information related to verifier error conditions on slice insert/extract type of o...
constexpr T real(const NonFloatComplex< T > &x)
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
TypeRange filterTypesOut(TypeRange types, const BitVector &indices, SmallVectorImpl< Type > &storage)
Filters out any elements referenced by indices.
constexpr T imag(const NonFloatComplex< T > &x)
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
AffineExpr makeCanonicalStridedLayoutExpr(ArrayRef< int64_t > sizes, ArrayRef< AffineExpr > exprs, MLIRContext *context)
Given MemRef sizes that are either static or dynamic, returns the canonical "contiguous" strides Affi...
std::optional< llvm::SmallDenseSet< unsigned > > computeRankReductionMask(ArrayRef< int64_t > originalShape, ArrayRef< int64_t > reducedShape, bool matchDynamic=false)
Given an originalShape and a reducedShape assumed to be a subset of originalShape with some 1 entries...
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
SliceVerificationResult isRankReducedType(ShapedType originalType, ShapedType candidateReducedType)
Check if originalType can be rank reduced to candidateReducedType type by dropping some dimensions wi...
TypeRange insertTypesInto(TypeRange oldTypes, ArrayRef< unsigned > indices, TypeRange newTypes, SmallVectorImpl< Type > &storage)
Insert a set of newTypes into oldTypes at the given indices.
llvm::function_ref< Fn > function_ref
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)