MLIR 22.0.0git
TypeUtilities.cpp
Go to the documentation of this file.
1//===- TypeUtilities.cpp - Helper function for type queries ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines generic type utilities.
10//
11//===----------------------------------------------------------------------===//
12
14#include "mlir/IR/Attributes.h"
16#include "mlir/IR/Types.h"
17#include "mlir/IR/Value.h"
18#include "llvm/ADT/SmallVectorExtras.h"
19#include <numeric>
20
21using namespace mlir;
22
24 if (auto st = llvm::dyn_cast<ShapedType>(type))
25 return st.getElementType();
26 return type;
27}
28
32
34 if (auto typedAttr = llvm::dyn_cast<TypedAttr>(attr))
35 return getElementTypeOrSelf(typedAttr.getType());
36 return {};
37}
38
41 t.getFlattenedTypes(fTypes);
42 return fTypes;
43}
44
45/// Return true if the specified type is an opaque type with the specified
46/// dialect and typeData.
47bool mlir::isOpaqueTypeWithName(Type type, StringRef dialect,
48 StringRef typeData) {
49 if (auto opaque = llvm::dyn_cast<mlir::OpaqueType>(type))
50 return opaque.getDialectNamespace() == dialect &&
51 opaque.getTypeData() == typeData;
52 return false;
53}
54
55/// Returns success if the given two shapes are compatible. That is, they have
56/// the same size and each pair of the elements are equal or one of them is
57/// dynamic.
59 ArrayRef<int64_t> shape2) {
60 if (shape1.size() != shape2.size())
61 return failure();
62 for (auto dims : llvm::zip(shape1, shape2)) {
63 int64_t dim1 = std::get<0>(dims);
64 int64_t dim2 = std::get<1>(dims);
65 if (ShapedType::isStatic(dim1) && ShapedType::isStatic(dim2) &&
66 dim1 != dim2)
67 return failure();
68 }
69 return success();
70}
71
72/// Returns success if the given two types have compatible shape. That is,
73/// they are both scalars (not shaped), or they are both shaped types and at
74/// least one is unranked or they have compatible dimensions. Dimensions are
75/// compatible if at least one is dynamic or both are equal. The element type
76/// does not matter.
77LogicalResult mlir::verifyCompatibleShape(Type type1, Type type2) {
78 auto sType1 = llvm::dyn_cast<ShapedType>(type1);
79 auto sType2 = llvm::dyn_cast<ShapedType>(type2);
80
81 // Either both or neither type should be shaped.
82 if (!sType1)
83 return success(!sType2);
84 if (!sType2)
85 return failure();
86
87 if (!sType1.hasRank() || !sType2.hasRank())
88 return success();
89
90 return verifyCompatibleShape(sType1.getShape(), sType2.getShape());
91}
92
93/// Returns success if the given two arrays have the same number of elements and
94/// each pair wise entries have compatible shape.
95LogicalResult mlir::verifyCompatibleShapes(TypeRange types1, TypeRange types2) {
96 if (types1.size() != types2.size())
97 return failure();
98 for (auto it : llvm::zip_first(types1, types2))
99 if (failed(verifyCompatibleShape(std::get<0>(it), std::get<1>(it))))
100 return failure();
101 return success();
102}
103
105 if (dims.empty())
106 return success();
107 auto staticDim =
108 llvm::accumulate(dims, dims.front(), [](auto fold, auto dim) {
109 return ShapedType::isDynamic(dim) ? fold : dim;
110 });
111 return success(llvm::all_of(dims, [&](auto dim) {
112 return ShapedType::isDynamic(dim) || dim == staticDim;
113 }));
114}
115
116/// Returns success if all given types have compatible shapes. That is, they are
117/// all scalars (not shaped), or they are all shaped types and any ranked shapes
118/// have compatible dimensions. Dimensions are compatible if all non-dynamic
119/// dims are equal. The element type does not matter.
121 auto shapedTypes = llvm::map_to_vector<8>(types, llvm::DynCastTo<ShapedType>);
122 // Return failure if some, but not all are not shaped. Return early if none
123 // are shaped also.
124 if (llvm::none_of(shapedTypes, [](auto t) { return t; }))
125 return success();
126 if (!llvm::all_of(shapedTypes, [](auto t) { return t; }))
127 return failure();
128
129 // Return failure if some, but not all, are scalable vectors.
130 bool hasScalableVecTypes = false;
131 bool hasNonScalableVecTypes = false;
132 for (Type t : types) {
133 auto vType = llvm::dyn_cast<VectorType>(t);
134 if (vType && vType.isScalable())
135 hasScalableVecTypes = true;
136 else
137 hasNonScalableVecTypes = true;
138 if (hasScalableVecTypes && hasNonScalableVecTypes)
139 return failure();
140 }
141
142 // Remove all unranked shapes
143 auto shapes = llvm::filter_to_vector<8>(
144 shapedTypes, [](auto shapedType) { return shapedType.hasRank(); });
145 if (shapes.empty())
146 return success();
147
148 // All ranks should be equal
149 auto firstRank = shapes.front().getRank();
150 if (llvm::any_of(shapes,
151 [&](auto shape) { return firstRank != shape.getRank(); }))
152 return failure();
153
154 for (unsigned i = 0; i < firstRank; ++i) {
155 // Retrieve all ranked dimensions
156 auto dims = llvm::map_to_vector<8>(
157 llvm::make_filter_range(
158 shapes, [&](auto shape) { return shape.getRank() >= i; }),
159 [&](auto shape) { return shape.getDimSize(i); });
160 if (verifyCompatibleDims(dims).failed())
161 return failure();
162 }
163
164 return success();
165}
166
168 return llvm::cast<ShapedType>(value.getType()).getElementType();
169}
170
172 return llvm::cast<ShapedType>(value.getType()).getElementType();
173}
174
176 TypeRange newTypes,
177 SmallVectorImpl<Type> &storage) {
178 assert(indices.size() == newTypes.size() &&
179 "mismatch between indice and type count");
180 if (indices.empty())
181 return oldTypes;
182
183 auto fromIt = oldTypes.begin();
184 for (auto it : llvm::zip(indices, newTypes)) {
185 const auto toIt = oldTypes.begin() + std::get<0>(it);
186 storage.append(fromIt, toIt);
187 storage.push_back(std::get<1>(it));
188 fromIt = toIt;
189 }
190 storage.append(fromIt, oldTypes.end());
191 return storage;
192}
193
195 SmallVectorImpl<Type> &storage) {
196 if (indices.none())
197 return types;
198
199 for (unsigned i = 0, e = types.size(); i < e; ++i)
200 if (!indices[i])
201 storage.emplace_back(types[i]);
202 return storage;
203}
return success()
Attributes are known-constant values of operations.
Definition Attributes.h:25
Type mapElement(Value value) const
Map the element to the iterator result type.
Type mapElement(Value value) const
Map the element to the iterator result type.
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
Include the generated interface declarations.
LogicalResult verifyCompatibleShapes(TypeRange types1, TypeRange types2)
Returns success if the given two arrays have the same number of elements and each pair wise entries h...
SmallVector< Type, 10 > getFlattenedTypes(TupleType t)
Get the types within a nested Tuple.
bool isOpaqueTypeWithName(Type type, StringRef dialect, StringRef typeData)
Return true if the specified type is an opaque type with the specified dialect and typeData.
TypeRange filterTypesOut(TypeRange types, const BitVector &indices, SmallVectorImpl< Type > &storage)
Filters out any elements referenced by indices.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
LogicalResult verifyCompatibleDims(ArrayRef< int64_t > dims)
Dimensions are compatible if all non-dynamic dims are equal.
LogicalResult verifyCompatibleShape(ArrayRef< int64_t > shape1, ArrayRef< int64_t > shape2)
Returns success if the given two shapes are compatible.
TypeRange insertTypesInto(TypeRange oldTypes, ArrayRef< unsigned > indices, TypeRange newTypes, SmallVectorImpl< Type > &storage)
Insert a set of newTypes into oldTypes at the given indices.