MLIR 23.0.0git
IndexingMapOpInterface.cpp
Go to the documentation of this file.
1//===- IndexingMapOpInterface.cpp -- IndexingMapOpInterface impl ----------===//
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
10
11using namespace mlir;
12
13namespace mlir {
14#include "mlir/Interfaces/IndexingMapOpInterface.cpp.inc"
15} // namespace mlir
16
17LogicalResult mlir::IndexingMapOpInterface::verifyImpl() {
18 // All input/output operands must be indexed.
19 if (static_cast<int64_t>(getIndexingMapsArray().size()) !=
20 getOperation()->getNumOperands())
21 return this->emitOpError("expected the number of indexing_map (")
22 << getIndexingMapsArray().size()
23 << ") to be equal to the number of input/output operands ("
24 << getOperation()->getNumOperands() << ")";
25
26 SmallVector<int64_t> allShapesSizes;
27
28 for (OpOperand &opOperand : getOperation()->getOpOperands()) {
29 AffineMap indexingMap = getMatchingIndexingMap(&opOperand);
30 SmallVector<int64_t> shape = getStaticOperandShape(&opOperand);
31 int64_t rank = shape.size();
32
33 // Symbols disallowed.
34 if (indexingMap.getNumSymbols() != 0)
35 return this->emitOpError("unexpected symbols in indexing_map #")
36 << opOperand.getOperandNumber();
37
38 // Result rank must match operand rank.
39 if (indexingMap.getNumResults() != rank)
40 return this->emitOpError("expected operand #")
41 << opOperand.getOperandNumber() << " rank (" << rank
42 << ") to match the result rank of indexing_map ("
43 << indexingMap.getNumResults() << ")";
44
45 llvm::append_range(allShapesSizes, shape);
46 }
47
48 AffineMap invertedMap = getShapesToLoopsMap();
49 if (!invertedMap) {
50 std::string str;
51 llvm::raw_string_ostream os(str);
52 getLoopsToShapesMap().print(os);
53 return this->emitOpError("invalid indexing maps are non-invertible: ")
54 << "(" << str << ")";
55 }
56
57 SmallVector<int64_t> endLoopRangeValues = invertedMap.compose(allShapesSizes);
58
59 // Check if given shapes match to inferred shapes.
60 SmallVector<int64_t> startLoopRangeValues(endLoopRangeValues.size(), 0);
61 // Verify only static cases since we can't get exact dimension sizes and
62 // loop ranges for dynamic cases in this stage.
63 if (llvm::none_of(endLoopRangeValues, ShapedType::isDynamic)) {
64 // Exclusive end range.
65 for (int64_t &range : endLoopRangeValues)
66 range -= 1;
67 for (OpOperand &opOperand : getOperation()->getOpOperands()) {
68 AffineMap indexingMap = getMatchingIndexingMap(&opOperand);
69 SmallVector<int64_t> startIndices =
70 indexingMap.compose(startLoopRangeValues);
71 SmallVector<int64_t> endIndices = indexingMap.compose(endLoopRangeValues);
72 SmallVector<int64_t> shape = getStaticOperandShape(&opOperand);
73 for (auto dim : llvm::seq<int64_t>(0, shape.size())) {
74 // Ignore dynamic dimension or the case that the dimension size is 0
75 if (ShapedType::isDynamic(shape[dim]) || shape[dim] == 0)
76 continue;
77
78 // The first index or last index should be the maximum or the minimum in
79 // the inferred index ranges since the range is increasing or
80 // decreasing. The size of dimensions of input/output operands and the
81 // maximum value + 1 in the inferred range should be the same. But, for
82 // now we check if the inferred ranges are in boundary of input/output
83 // operands' size or not in case that Affine Expressions are complicated
84 // such as d0 * 3
85 // + d1 since it is not easy to handle the issues.
86 // Found the case that this solution can't check, for example, (d0, d1)
87 // -> (d1 - d0)
88 int64_t inferredDimSize =
89 std::max(startIndices[dim], endIndices[dim]) + 1;
90 if (std::min(startIndices[dim], endIndices[dim]) < 0) {
91 std::string mapStr;
92 {
93 llvm::raw_string_ostream os(mapStr);
94 os << indexingMap;
95 }
96 return this->emitOpError(
97 "unexpected result less than 0 at expression #")
98 << dim << " in " << mapStr;
99 }
100 if (isa<AffineDimExpr>(indexingMap.getResult(dim))) {
101 if (inferredDimSize != shape[dim]) {
102 return this->emitOpError("inferred input/output operand #")
103 << opOperand.getOperandNumber() << " has shape's dimension #"
104 << dim << " to be " << inferredDimSize << ", but found "
105 << shape[dim];
106 }
107 } else {
108 if (inferredDimSize > shape[dim]) {
109 return this->emitOpError("inferred input/output operand #")
110 << opOperand.getOperandNumber() << " has shape's dimension #"
111 << dim << " to be greater than or equal to "
112 << inferredDimSize << ", but found " << shape[dim];
113 }
114 }
115 }
116 }
117 }
118
119 return success();
120}
return success()
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
unsigned getNumSymbols() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
This class represents an operand of an operation.
Definition Value.h:257
Include the generated interface declarations.