MLIR 22.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 AffineMap invertedMap = getShapesToLoopsMap();
27 if (!invertedMap) {
28 std::string str;
29 llvm::raw_string_ostream os(str);
30 getLoopsToShapesMap().print(os);
31 return this->emitOpError("invalid indexing maps are non-invertible: ")
32 << "(" << str << ")";
33 }
34
35 SmallVector<int64_t> endLoopRangeValues = getStaticLoopRanges();
36
37 // Set this flag if this op has user defined maps. This is required to guard
38 // the below error condition which assume default indexing maps.
39 for (OpOperand &opOperand : getOperation()->getOpOperands()) {
40 AffineMap indexingMap = getMatchingIndexingMap(&opOperand);
41
42 // Symbols disallowed.
43 if (indexingMap.getNumSymbols() != 0)
44 return getOperation()->emitOpError("unexpected symbols in indexing_map #")
45 << opOperand.getOperandNumber();
46
47 // Domain must be consistent.
48 if (indexingMap.getNumDims() != endLoopRangeValues.size())
49 return getOperation()->emitOpError("expected indexing_map #")
50 << opOperand.getOperandNumber() << " to have "
51 << endLoopRangeValues.size()
52 << " dim(s) to match the number of loops";
53
54 SmallVector<int64_t> shape = getStaticOperandShape(&opOperand);
55 int64_t rank = shape.size();
56
57 if (indexingMap.getNumResults() != rank)
58 return getOperation()->emitOpError("expected operand rank (")
59 << rank << ") to match the result rank of indexing_map #"
60 << opOperand.getOperandNumber() << " ("
61 << indexingMap.getNumResults() << ")";
62 }
63
64 // Check if given shapes match to inferred shapes.
65 SmallVector<int64_t> startLoopRangeValues(endLoopRangeValues.size(), 0);
66 // Verify only static cases since we can't get exact dimension sizes and
67 // loop ranges for dynamic cases in this stage.
68 if (llvm::none_of(endLoopRangeValues, ShapedType::isDynamic)) {
69 // Exclusive end range.
70 for (int64_t &range : endLoopRangeValues)
71 range -= 1;
72 for (OpOperand &opOperand : getOperation()->getOpOperands()) {
73 AffineMap indexingMap = getMatchingIndexingMap(&opOperand);
74 SmallVector<int64_t> startIndices =
75 indexingMap.compose(startLoopRangeValues);
76 SmallVector<int64_t> endIndices = indexingMap.compose(endLoopRangeValues);
77 SmallVector<int64_t> shape = getStaticOperandShape(&opOperand);
78 for (auto dim : llvm::seq<int64_t>(0, shape.size())) {
79 // Ignore dynamic dimension or the case that the dimension size is 0
80 if (ShapedType::isDynamic(shape[dim]) || shape[dim] == 0)
81 continue;
82
83 // The first index or last index should be the maximum or the minimum in
84 // the inferred index ranges since the range is increasing or
85 // decreasing. The size of dimensions of input/output operands and the
86 // maximum value + 1 in the inferred range should be the same. But, for
87 // now we check if the inferred ranges are in boundary of input/output
88 // operands' size or not in case that Affine Expressions are complicated
89 // such as d0 * 3
90 // + d1 since it is not easy to handle the issues.
91 // Found the case that this solution can't check, for example, (d0, d1)
92 // -> (d1 - d0)
93 int64_t inferredDimSize =
94 std::max(startIndices[dim], endIndices[dim]) + 1;
95 if (std::min(startIndices[dim], endIndices[dim]) < 0) {
96 std::string mapStr;
97 {
98 llvm::raw_string_ostream os(mapStr);
99 os << indexingMap;
100 }
101 return this->emitOpError(
102 "unexpected result less than 0 at expression #")
103 << dim << " in " << mapStr;
104 }
105 if (isa<AffineDimExpr>(indexingMap.getResult(dim))) {
106 if (inferredDimSize != shape[dim]) {
107 return this->emitOpError("inferred input/output operand #")
108 << opOperand.getOperandNumber() << " has shape's dimension #"
109 << dim << " to be " << inferredDimSize << ", but found "
110 << shape[dim];
111 }
112 } else {
113 if (inferredDimSize > shape[dim]) {
114 return this->emitOpError("inferred input/output operand #")
115 << opOperand.getOperandNumber() << " has shape's dimension #"
116 << dim << " to be greater than or equal to "
117 << inferredDimSize << ", but found " << shape[dim];
118 }
119 }
120 }
121 }
122 }
123
124 return success();
125}
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 getNumDims() 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.