10#include "TypeDetail.h"
21#include "llvm/ADT/APFixedPoint.h"
22#include "llvm/ADT/APFloat.h"
23#include "llvm/ADT/APInt.h"
24#include "llvm/ADT/Sequence.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/CheckedArithmetic.h"
36#define GET_TYPEDEF_CLASSES
37#include "mlir/IR/BuiltinTypes.cpp.inc"
40#include "mlir/IR/BuiltinTypeConstraints.cpp.inc"
47void BuiltinDialect::registerTypes() {
49#define GET_TYPEDEF_LIST
50#include "mlir/IR/BuiltinTypes.cpp.inc"
62 return emitError() <<
"invalid element type for complex";
66size_t ComplexType::getDenseElementBitSize()
const {
68 return llvm::alignTo<8>(elemTy.getDenseElementBitSize()) * 2;
73 size_t singleElementBytes =
74 llvm::alignTo<8>(elemTy.getDenseElementBitSize()) / 8;
76 elemTy.convertToAttribute(rawData.take_front(singleElementBytes));
78 elemTy.convertToAttribute(rawData.take_back(singleElementBytes));
83ComplexType::convertFromAttribute(
Attribute attr,
85 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
86 if (!arrayAttr || arrayAttr.size() != 2)
90 if (
failed(elemTy.convertFromAttribute(arrayAttr[0], realData)))
92 if (
failed(elemTy.convertFromAttribute(arrayAttr[1], imagData)))
106 SignednessSemantics signedness) {
107 if (width > IntegerType::kMaxWidth) {
108 return emitError() <<
"integer bitwidth is limited to "
109 << IntegerType::kMaxWidth <<
" bits";
114unsigned IntegerType::getWidth()
const {
return getImpl()->width; }
116IntegerType::SignednessSemantics IntegerType::getSignedness()
const {
117 return getImpl()->signedness;
120IntegerType IntegerType::scaleElementBitwidth(
unsigned scale) {
122 return IntegerType();
123 return IntegerType::get(
getContext(), scale * getWidth(), getSignedness());
126size_t IntegerType::getDenseElementBitSize()
const {
132 APInt value = detail::readBits(rawData.data(), 0, getWidth());
133 return IntegerAttr::get(*
this, value);
137 size_t byteSize = llvm::divideCeil(apInt.getBitWidth(), CHAR_BIT);
138 size_t bitPos =
result.size() * CHAR_BIT;
144IntegerType::convertFromAttribute(
Attribute attr,
146 auto intAttr = dyn_cast<IntegerAttr>(attr);
147 if (!intAttr || intAttr.getType() != *
this)
157llvm::FixedPointSemantics MXI8Type::getFixedPointSemantics() {
163size_t MXI8Type::getDenseElementBitSize()
const {
return 8; }
166 return IntegerType::get(
getContext(), 8).convertToAttribute(rawData);
170MXI8Type::convertFromAttribute(
Attribute attr,
172 auto intAttr = dyn_cast<IntegerAttr>(attr);
173 if (!intAttr || !intAttr.getType().isSignlessInteger(8))
175 return cast<IntegerType>(intAttr.getType())
176 .convertFromAttribute(attr,
result);
183size_t IndexType::getDenseElementBitSize()
const {
184 return kInternalStorageBitWidth;
189 detail::readBits(rawData.data(), 0, kInternalStorageBitWidth);
190 return IntegerAttr::get(*
this, value);
194IndexType::convertFromAttribute(
Attribute attr,
196 auto intAttr = dyn_cast<IntegerAttr>(attr);
197 if (!intAttr || intAttr.getType() != *
this)
208#define FLOAT_TYPE_SEMANTICS(TYPE, SEM) \
209 const llvm::fltSemantics &TYPE::getFloatSemantics() const { \
210 return APFloat::SEM(); \
231#undef FLOAT_TYPE_SEMANTICS
233FloatType Float16Type::scaleElementBitwidth(
unsigned scale)
const {
241FloatType BFloat16Type::scaleElementBitwidth(
unsigned scale)
const {
249FloatType Float32Type::scaleElementBitwidth(
unsigned scale)
const {
259unsigned FunctionType::getNumInputs()
const {
return getImpl()->numInputs; }
262 return getImpl()->getInputs();
265unsigned FunctionType::getNumResults()
const {
return getImpl()->numResults; }
268 return getImpl()->getResults();
277FunctionType FunctionType::getWithArgsAndResults(
284 insertTypesInto(getResults(), resultIndices, resultTypes, resultStorage);
285 return clone(newArgTypes, newResultTypes);
290FunctionType::getWithoutArgsAndResults(
const BitVector &argIndices,
291 const BitVector &resultIndices) {
296 return clone(newArgTypes, newResultTypes);
303unsigned GraphType::getNumInputs()
const {
return getImpl()->numInputs; }
305ArrayRef<Type> GraphType::getInputs()
const {
return getImpl()->getInputs(); }
307unsigned GraphType::getNumResults()
const {
return getImpl()->numResults; }
309ArrayRef<Type> GraphType::getResults()
const {
return getImpl()->getResults(); }
325 insertTypesInto(getResults(), resultIndices, resultTypes, resultStorage);
326 return clone(newArgTypes, newResultTypes);
330GraphType GraphType::getWithoutArgsAndResults(
const BitVector &argIndices,
331 const BitVector &resultIndices) {
336 return clone(newArgTypes, newResultTypes);
344 StringAttr dialect, StringRef typeData) {
346 return emitError() <<
"invalid dialect namespace '" << dialect <<
"'";
353 <<
"`!" << dialect <<
"<\"" << typeData <<
"\">"
354 <<
"` type created with unregistered dialect. If this is "
355 "intended, please call allowUnregisteredDialects() on the "
356 "MLIRContext, or use -allow-unregistered-dialect with "
357 "the MLIR opt tool used";
367bool VectorType::isValidElementType(
Type t) {
374 if (!isValidElementType(elementType))
376 <<
"vector elements must be int/index/float type but got "
379 if (any_of(shape, [](int64_t i) {
return i <= 0; }))
381 <<
"vector types must have positive constant sizes but got "
384 if (scalableDims.size() != shape.size())
385 return emitError() <<
"number of dims must match, got "
386 << scalableDims.size() <<
" and " << shape.size();
391VectorType VectorType::scaleElementBitwidth(
unsigned scale) {
395 if (
auto scaledEt = et.scaleElementBitwidth(scale))
396 return VectorType::get(
getShape(), scaledEt, getScalableDims());
398 if (
auto scaledEt = et.scaleElementBitwidth(scale))
399 return VectorType::get(
getShape(), scaledEt, getScalableDims());
404 Type elementType)
const {
405 return VectorType::get(shape.value_or(
getShape()), elementType,
415 .Case<RankedTensorType, UnrankedTensorType>(
416 [](
auto type) {
return type.getElementType(); });
420 return !llvm::isa<UnrankedTensorType>(*
this);
424 return llvm::cast<RankedTensorType>(*this).getShape();
428 Type elementType)
const {
429 if (llvm::dyn_cast<UnrankedTensorType>(*
this)) {
431 return RankedTensorType::get(*
shape, elementType);
432 return UnrankedTensorType::get(elementType);
435 auto rankedTy = llvm::cast<RankedTensorType>(*
this);
437 return RankedTensorType::get(rankedTy.getShape(), elementType,
438 rankedTy.getEncoding());
439 return RankedTensorType::get(
shape.value_or(rankedTy.getShape()), elementType,
440 rankedTy.getEncoding());
444 Type elementType)
const {
445 return ::llvm::cast<RankedTensorType>(
cloneWith(
shape, elementType));
457 return emitError() <<
"invalid tensor element type: " << elementType;
466 return llvm::isa<ComplexType, FloatType, IntegerType, OpaqueType, VectorType,
467 IndexType, MXI8Type>(type) ||
468 !llvm::isa<BuiltinDialect>(type.
getDialect());
480 if (s < 0 && ShapedType::isStatic(s))
481 return emitError() <<
"invalid tensor dimension size";
482 if (
auto v = llvm::dyn_cast_or_null<VerifiableTensorEncoding>(encoding))
505 [](
auto type) {
return type.getElementType(); });
509 return !llvm::isa<UnrankedMemRefType>(*
this);
513 return llvm::cast<MemRefType>(*this).getShape();
517 Type elementType)
const {
518 if (llvm::dyn_cast<UnrankedMemRefType>(*
this)) {
533FailureOr<PtrLikeTypeInterface>
535 std::optional<Type> elementType)
const {
537 if (llvm::dyn_cast<UnrankedMemRefType>(*
this))
538 return cast<PtrLikeTypeInterface>(
539 UnrankedMemRefType::get(eTy, memorySpace));
544 return cast<PtrLikeTypeInterface>(
static_cast<MemRefType
>(builder));
548 Type elementType)
const {
557 if (
auto rankedMemRefTy = llvm::dyn_cast<MemRefType>(*
this))
558 return rankedMemRefTy.getMemorySpace();
559 return llvm::cast<UnrankedMemRefType>(*this).getMemorySpace();
563 if (
auto rankedMemRefTy = llvm::dyn_cast<MemRefType>(*
this))
564 return rankedMemRefTy.getMemorySpaceAsInt();
565 return llvm::cast<UnrankedMemRefType>(*this).getMemorySpaceAsInt();
572std::optional<llvm::SmallDenseSet<unsigned>>
576 size_t originalRank = originalShape.size(), reducedRank = reducedShape.size();
577 llvm::SmallDenseSet<unsigned> unusedDims;
578 unsigned reducedIdx = 0;
579 for (
unsigned originalIdx = 0; originalIdx < originalRank; ++originalIdx) {
581 int64_t origSize = originalShape[originalIdx];
583 if (matchDynamic && reducedIdx < reducedRank && origSize != 1 &&
584 (ShapedType::isDynamic(reducedShape[reducedIdx]) ||
585 ShapedType::isDynamic(origSize))) {
589 if (reducedIdx < reducedRank && origSize == reducedShape[reducedIdx]) {
594 unusedDims.insert(originalIdx);
601 if (reducedIdx != reducedRank)
608 ShapedType candidateReducedType) {
609 if (originalType == candidateReducedType)
612 ShapedType originalShapedType = llvm::cast<ShapedType>(originalType);
613 ShapedType candidateReducedShapedType =
614 llvm::cast<ShapedType>(candidateReducedType);
619 candidateReducedShapedType.getShape();
620 unsigned originalRank = originalShape.size(),
621 candidateReducedRank = candidateReducedShape.size();
622 if (candidateReducedRank > originalRank)
625 auto optionalUnusedDimsMask =
629 if (!optionalUnusedDimsMask)
632 if (originalShapedType.getElementType() !=
633 candidateReducedShapedType.getElementType())
641 if (memorySpace == 0)
644 return IntegerAttr::get(IntegerType::get(ctx, 64), memorySpace);
648 IntegerAttr intMemorySpace = llvm::dyn_cast_or_null<IntegerAttr>(memorySpace);
649 if (intMemorySpace && intMemorySpace.getValue() == 0)
659 assert(llvm::isa<IntegerAttr>(memorySpace) &&
660 "Using `getMemorySpaceInteger` with non-Integer attribute");
662 return static_cast<unsigned>(llvm::cast<IntegerAttr>(memorySpace).getInt());
665unsigned MemRefType::getMemorySpaceAsInt()
const {
670 MemRefLayoutAttrInterface layout,
684MemRefType MemRefType::getChecked(
686 Type elementType, MemRefLayoutAttrInterface layout,
Attribute memorySpace) {
697 elementType, layout, memorySpace);
709 auto layout = AffineMapAttr::get(map);
729 auto layout = AffineMapAttr::get(map);
735 elementType, layout, memorySpace);
739 AffineMap map,
unsigned memorySpaceInd) {
747 auto layout = AffineMapAttr::get(map);
760 unsigned memorySpaceInd) {
768 auto layout = AffineMapAttr::get(map);
775 elementType, layout, memorySpace);
780 MemRefLayoutAttrInterface layout,
783 return emitError() <<
"invalid memref element type";
786 for (int64_t s :
shape)
787 if (s < 0 && ShapedType::isStatic(s))
788 return emitError() <<
"invalid memref size";
790 assert(layout &&
"missing layout specification");
797bool MemRefType::areTrailingDimsContiguous(int64_t n) {
798 assert(n <= getRank() &&
799 "number of dimensions to check must not exceed rank");
800 return n <= getNumContiguousTrailingDims();
803int64_t MemRefType::getNumContiguousTrailingDims() {
804 const int64_t n = getRank();
807 if (getLayout().isIdentity())
825 int64_t dimProduct = 1;
826 for (int64_t i = n - 1; i >= 0; --i) {
829 if (strides[i] != dimProduct)
831 if (
shape[i] == ShapedType::kDynamic)
833 dimProduct *=
shape[i];
839MemRefType MemRefType::canonicalizeStridedLayout() {
840 AffineMap m = getLayout().getAffineMap();
852 if (
auto cst = llvm::dyn_cast<AffineConstantExpr>(m.
getResult(0)))
853 if (cst.getValue() == 0)
868 auto simplifiedLayoutExpr =
870 if (expr != simplifiedLayoutExpr)
873 simplifiedLayoutExpr)));
878 int64_t &offset)
const {
879 return getLayout().getStridesAndOffset(
getShape(), strides, offset);
882std::pair<SmallVector<int64_t>, int64_t>
883MemRefType::getStridesAndOffset()
const {
888 assert(succeeded(status) &&
"Invalid use of check-free getStridesAndOffset");
889 return {strides, offset};
892bool MemRefType::isStrided() {
896 return succeeded(res);
899bool MemRefType::isLastDimUnitStride() {
903 return succeeded(successStrides) && (strides.empty() || strides.back() == 1);
910unsigned UnrankedMemRefType::getMemorySpaceAsInt()
const {
918 return emitError() <<
"invalid memref element type";
928ArrayRef<Type> TupleType::getTypes()
const {
return getImpl()->getTypes(); }
935 for (
Type type : getTypes()) {
936 if (
auto nestedTuple = llvm::dyn_cast<TupleType>(type))
937 nestedTuple.getFlattenedTypes(types);
939 types.push_back(type);
944size_t TupleType::size()
const {
return getImpl()->size(); }
957 assert(!exprs.empty() &&
"expected exprs");
959 assert(!maps.empty() &&
"Expected one non-empty map");
960 unsigned numDims = maps[0].getNumDims(), nSymbols = maps[0].getNumSymbols();
963 bool dynamicPoisonBit =
false;
965 for (
auto en : llvm::zip(llvm::reverse(exprs), llvm::reverse(sizes))) {
966 int64_t size = std::get<1>(en);
971 expr = expr ? expr + dimExpr * stride : dimExpr * stride;
973 auto result = llvm::checkedMul(runningSize, size);
976 dynamicPoisonBit =
true;
981 dynamicPoisonBit =
true;
990 exprs.reserve(sizes.size());
991 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.
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)