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) {
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())
617 if (llvm::isa<IntegerAttr, StringAttr, DictionaryAttr>(memorySpace))
621 if (!isa<BuiltinDialect>(memorySpace.
getDialect()))
629 if (memorySpace == 0)
632 return IntegerAttr::get(IntegerType::get(ctx, 64), memorySpace);
636 IntegerAttr intMemorySpace = llvm::dyn_cast_or_null<IntegerAttr>(memorySpace);
637 if (intMemorySpace && intMemorySpace.getValue() == 0)
647 assert(llvm::isa<IntegerAttr>(memorySpace) &&
648 "Using `getMemorySpaceInteger` with non-Integer attribute");
650 return static_cast<unsigned>(llvm::cast<IntegerAttr>(memorySpace).getInt());
653unsigned MemRefType::getMemorySpaceAsInt()
const {
658 MemRefLayoutAttrInterface layout,
672MemRefType MemRefType::getChecked(
674 Type elementType, MemRefLayoutAttrInterface layout,
Attribute memorySpace) {
685 elementType, layout, memorySpace);
697 auto layout = AffineMapAttr::get(map);
717 auto layout = AffineMapAttr::get(map);
723 elementType, layout, memorySpace);
727 AffineMap map,
unsigned memorySpaceInd) {
735 auto layout = AffineMapAttr::get(map);
748 unsigned memorySpaceInd) {
756 auto layout = AffineMapAttr::get(map);
763 elementType, layout, memorySpace);
768 MemRefLayoutAttrInterface layout,
771 return emitError() <<
"invalid memref element type";
774 for (int64_t s :
shape)
775 if (s < 0 && ShapedType::isStatic(s))
776 return emitError() <<
"invalid memref size";
778 assert(layout &&
"missing layout specification");
783 return emitError() <<
"unsupported memory space Attribute";
788bool MemRefType::areTrailingDimsContiguous(int64_t n) {
789 assert(n <= getRank() &&
790 "number of dimensions to check must not exceed rank");
791 return n <= getNumContiguousTrailingDims();
794int64_t MemRefType::getNumContiguousTrailingDims() {
795 const int64_t n = getRank();
798 if (getLayout().isIdentity())
816 int64_t dimProduct = 1;
817 for (int64_t i = n - 1; i >= 0; --i) {
820 if (strides[i] != dimProduct)
822 if (
shape[i] == ShapedType::kDynamic)
824 dimProduct *=
shape[i];
830MemRefType MemRefType::canonicalizeStridedLayout() {
831 AffineMap m = getLayout().getAffineMap();
843 if (
auto cst = llvm::dyn_cast<AffineConstantExpr>(m.
getResult(0)))
844 if (cst.getValue() == 0)
859 auto simplifiedLayoutExpr =
861 if (expr != simplifiedLayoutExpr)
864 simplifiedLayoutExpr)));
869 int64_t &offset)
const {
870 return getLayout().getStridesAndOffset(
getShape(), strides, offset);
873std::pair<SmallVector<int64_t>, int64_t>
874MemRefType::getStridesAndOffset()
const {
879 assert(succeeded(status) &&
"Invalid use of check-free getStridesAndOffset");
880 return {strides, offset};
883bool MemRefType::isStrided() {
887 return succeeded(res);
890bool MemRefType::isLastDimUnitStride() {
894 return succeeded(successStrides) && (strides.empty() || strides.back() == 1);
901unsigned UnrankedMemRefType::getMemorySpaceAsInt()
const {
909 return emitError() <<
"invalid memref element type";
912 return emitError() <<
"unsupported memory space Attribute";
922ArrayRef<Type> TupleType::getTypes()
const {
return getImpl()->getTypes(); }
929 for (
Type type : getTypes()) {
930 if (
auto nestedTuple = llvm::dyn_cast<TupleType>(type))
931 nestedTuple.getFlattenedTypes(types);
933 types.push_back(type);
938size_t TupleType::size()
const {
return getImpl()->size(); }
951 assert(!exprs.empty() &&
"expected exprs");
953 assert(!maps.empty() &&
"Expected one non-empty map");
954 unsigned numDims = maps[0].getNumDims(), nSymbols = maps[0].getNumSymbols();
957 bool dynamicPoisonBit =
false;
959 for (
auto en : llvm::zip(llvm::reverse(exprs), llvm::reverse(sizes))) {
960 int64_t size = std::get<1>(en);
965 expr = expr ? expr + dimExpr * stride : dimExpr * stride;
967 auto result = llvm::checkedMul(runningSize, size);
970 dynamicPoisonBit =
true;
975 dynamicPoisonBit =
true;
984 exprs.reserve(sizes.size());
985 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)
Determine the element type of type.
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.
Dialect & getDialect() const
Get the dialect this attribute is registered to.
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.
bool isSupportedMemorySpace(Attribute memorySpace)
Checks if the memorySpace has supported Attribute type.
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.
bool isValidVectorTypeElementType(::mlir::Type type)
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)