[Mlir-commits] [mlir] f4f7bc1 - [mlir][linalg] Cleanup LinalgOp usage in verification (NFC).
Tobias Gysi
llvmlistbot at llvm.org
Mon May 31 07:28:08 PDT 2021
Author: Tobias Gysi
Date: 2021-05-31T14:25:45Z
New Revision: f4f7bc17374ef79646ffc97a204abc8377187f16
URL: https://github.com/llvm/llvm-project/commit/f4f7bc17374ef79646ffc97a204abc8377187f16
DIFF: https://github.com/llvm/llvm-project/commit/f4f7bc17374ef79646ffc97a204abc8377187f16.diff
LOG: [mlir][linalg] Cleanup LinalgOp usage in verification (NFC).
Replace the uses of deprecated Structured Op Interface methods in LinalgInterfaces.cpp. This patch is based on https://reviews.llvm.org/D103394.
Differential Revision: https://reviews.llvm.org/D103404
Added:
Modified:
mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp
Removed:
################################################################################
diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp
index c7372cdc9760..aec76094e045 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgInterfaces.cpp
@@ -12,6 +12,7 @@
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/AffineExprVisitor.h"
#include "mlir/IR/AffineMap.h"
+#include "mlir/IR/TypeUtilities.h"
#include "llvm/ADT/SmallSet.h"
using namespace mlir;
@@ -321,19 +322,19 @@ LogicalResult LinalgOp::reifyReturnTypeShapesPerResultDim(
LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
LinalgOp linalgOp = cast<LinalgOp>(op);
- // Expect at least one shaped operand.
+ // Expect at least one input/output operand.
// This means an op that constructs a tensor out of indices cannot be a
// LinalgOp at the moment. For now this will have to be a special op until we
// have output shape operands that are not tensors.
- auto nShapedOperands = linalgOp.getNumShapedOperands();
- if (nShapedOperands == 0)
- return linalgOp.emitOpError("expected at least 1 Shaped operand");
- if (failed(OpTrait::impl::verifyAtLeastNOperands(op, nShapedOperands)))
+ int64_t numInputsAndOutputs = linalgOp.getNumInputsAndOutputs();
+ if (numInputsAndOutputs == 0)
+ return op->emitOpError("expected at least one input/output operand");
+ if (failed(OpTrait::impl::verifyAtLeastNOperands(op, numInputsAndOutputs)))
return failure();
// Should have at least one output tensor per result tensor.
// Can also have outbut buffers that do not correspond to results.
- if (op->getNumResults() > linalgOp.getNumOutputTensors())
- return op->emitError("unexpected #results > #outputs");
+ if (op->getNumResults() > linalgOp.getOutputTensorOperands().size())
+ return op->emitOpError("unexpected #results > #outputs");
// Before checking indexing maps, we need to make sure the attributes
// referenced by it are valid.
@@ -342,66 +343,66 @@ LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
return failure();
// All shaped operands must be indexed.
- if (linalgOp.indexing_maps().size() != linalgOp.getNumShapedOperands())
- return linalgOp.emitOpError("expected the number of indexing_map (")
+ if (linalgOp.indexing_maps().size() != linalgOp.getNumInputsAndOutputs())
+ return op->emitOpError("expected the number of indexing_map (")
<< linalgOp.indexing_maps().size()
- << ") to be equal to the number of shaped operands ("
- << linalgOp.getNumShapedOperands() << ")";
+ << ") to be equal to the number of input/output operands ("
+ << linalgOp.getNumInputsAndOutputs() << ")";
- SmallVector<AffineMap, 4> indexingMaps;
- indexingMaps.reserve(linalgOp.indexing_maps().size());
- for (auto en : llvm::enumerate(linalgOp.indexing_maps())) {
- auto idx = en.index();
- auto m = en.value().template cast<AffineMapAttr>().getValue();
- indexingMaps.push_back(m); // Save reference to map for further checks.
- auto shapedValue = linalgOp.getShapedType(idx);
+ for (OpOperand *opOperand : linalgOp.getInputAndOutputOperands()) {
+ AffineMap indexingMap = linalgOp.getTiedIndexingMap(opOperand);
// Symbols disallowed.
- if (m.getNumSymbols() != 0)
- return linalgOp.emitOpError("unexpected symbols in indexing_map #")
- << idx;
+ if (indexingMap.getNumSymbols() != 0)
+ return op->emitOpError("unexpected symbols in indexing_map #")
+ << opOperand->getOperandNumber();
// Domain must be consistent.
- auto nLoops = linalgOp.getNumLoops();
- if (m.getNumDims() != nLoops)
- return linalgOp.emitOpError("expected indexing_map #")
- << idx << " to have " << nLoops
+ unsigned numLoops = linalgOp.getNumLoops();
+ if (indexingMap.getNumDims() != numLoops)
+ return op->emitOpError("expected indexing_map #")
+ << opOperand->getOperandNumber() << " to have " << numLoops
<< " dim(s) to match the number of loops";
- if (m.getNumResults() != shapedValue.getRank())
- return linalgOp.emitOpError("expected shaped value rank (")
- << shapedValue.getRank()
- << ") to match the result rank of indexing_map #" << idx << " ("
- << m.getNumResults() << ")";
+ int64_t rank = linalgOp.getRank(opOperand);
+ if (indexingMap.getNumResults() != rank)
+ return op->emitOpError("expected shaped value rank (")
+ << rank << ") to match the result rank of indexing_map #"
+ << opOperand->getOperandNumber() << " ("
+ << indexingMap.getNumResults() << ")";
}
- SmallVector<AffineExpr, 4> redDims;
+ SmallVector<AffineExpr> redDims;
linalgOp.getReductionDims(redDims);
// Simplifying assumption: either full tensor or full buffer mode.
// This allows simpler verification of output operands vs result types
// without premature tracking of which operand is what in mixed-mode.
// TODO: relax when mixed-mode needs to pass verification.
- if (linalgOp.getNumOutputBuffers() > 0 && linalgOp.getNumOutputTensors() > 0)
- return op->emitError("expected output operands to all have tensor type or "
- "all have buffer type");
-
- for (auto it :
- llvm::zip(linalgOp.getOutputOpOperands(), op->getResultTypes())) {
- if (!std::get<0>(it).get().getType().isa<RankedTensorType>())
+ if (!linalgOp.getOutputBufferOperands().empty() &&
+ !linalgOp.getOutputTensorOperands().empty())
+ return op->emitOpError(
+ "expected output operands to all have tensor type or "
+ "all have buffer type");
+
+ for (OpOperand *opOperand : linalgOp.getOutputTensorOperands()) {
+ // TODO: Enforce one output tensor per result?
+ if (opOperand->getOperandNumber() - linalgOp.getNumInputs() >=
+ linalgOp->getNumResults())
continue;
- if (std::get<0>(it).get().getType() != std::get<1>(it))
- return op->emitError("expected type of operand #")
- << std::get<0>(it).getOperandNumber() << " ("
- << std::get<0>(it).get().getType() << ")"
- << " to match type of corresponding result (" << std::get<1>(it)
+ OpResult result = linalgOp.getTiedOpResult(opOperand);
+ if (result.getType() != opOperand->get().getType())
+ return op->emitOpError("expected type of operand #")
+ << opOperand->getOperandNumber() << " ("
+ << opOperand->get().getType() << ")"
+ << " to match type of corresponding result (" << result.getType()
<< ")";
}
// Output tensor indexing map may not depend on reduction indices.
- for (OpOperand &opOperand : linalgOp.getOutputOpOperands()) {
- AffineMap outputMap = linalgOp.getIndexingMap(opOperand.getOperandNumber());
- for (auto expr : outputMap.getResults()) {
+ for (OpOperand *opOperand : linalgOp.getOutputOperands()) {
+ AffineMap indexingMap = linalgOp.getTiedIndexingMap(opOperand);
+ for (auto expr : indexingMap.getResults()) {
for (auto dim : redDims) {
unsigned pos = dim.cast<AffineDimExpr>().getPosition();
if (expr.isFunctionOfDim(pos)) {
@@ -410,9 +411,9 @@ LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
llvm::raw_string_ostream os(exprStr);
os << expr;
}
- return op->emitError(
+ return op->emitOpError(
"unexpected output tensor expression in indexing map #")
- << (opOperand.getOperandNumber() - linalgOp.getNumInputs())
+ << (opOperand->getOperandNumber() - linalgOp.getNumInputs())
<< " a.k.a '" << exprStr
<< "' is function of reduction iterator 'd" << pos << "'";
}
@@ -444,49 +445,49 @@ LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
Block &block = linalgOp->getRegion(0).front();
unsigned numBBIvs = linalgOp.getNumPayloadInductionVariables();
- if (linalgOp.getNumShapedOperands() + numBBIvs != block.getNumArguments())
- return op->emitError("expected as many non-induction variable region "
- "arguments as the number of shaped operands");
+ if (linalgOp.getNumInputsAndOutputs() + numBBIvs != block.getNumArguments())
+ return op->emitOpError("expected as many non-induction variable region "
+ "arguments as the number of shaped operands");
// Note: the number and type of yield values are checked in the YieldOp.
for (unsigned i = 0; i < numBBIvs; ++i)
if (!block.getArgument(i).getType().isIndex())
return op->emitOpError("expected index block argument #") << i;
- unsigned idx = 0;
- for (auto it : llvm::zip(linalgOp.getShapedOperandTypes(),
- block.getArguments().drop_front(numBBIvs))) {
- if (std::get<0>(it).getElementType() != std::get<1>(it).getType())
- return op->emitError("expected type of bb argument #")
- << (idx + numBBIvs) << " (" << std::get<1>(it).getType() << ")"
+ for (OpOperand *opOperand : linalgOp.getInputAndOutputOperands()) {
+ Type elementType = getElementTypeOrSelf(opOperand->get().getType());
+ Type argType =
+ block.getArgument(numBBIvs + opOperand->getOperandNumber()).getType();
+ if (elementType != argType)
+ return op->emitOpError("expected type of bb argument #")
+ << numBBIvs + opOperand->getOperandNumber() << " (" << argType
+ << ")"
<< " to match element type of corresponding shaped operand ("
- << std::get<0>(it).getElementType() << ")";
- ++idx;
+ << elementType << ")";
}
// Check if given shapes match to inferred shapes.
Optional<SmallVector<int64_t, 4>> endLoopRangeValues =
linalgOp.getStaticLoopRanges();
if (!endLoopRangeValues)
- return linalgOp.emitError("unable to find loop range for operation");
+ return op->emitOpError("unable to find loop range for operation");
SmallVector<int64_t, 4> startLoopRangeValues((*endLoopRangeValues).size(), 0);
// Verify only static cases since we can't get exact dimension sizes and loop
// ranges for dynamic cases in this stage.
- if (llvm::none_of(*endLoopRangeValues, [](int64_t &range) {
- return range == ShapedType::kDynamicSize;
- })) {
+ if (llvm::none_of(*endLoopRangeValues, ShapedType::isDynamic)) {
for (int64_t &range : *endLoopRangeValues)
range -= 1;
- for (const auto &en : llvm::enumerate(linalgOp.getShapedOperandTypes())) {
- auto startIndices =
- indexingMaps[en.index()].compose(startLoopRangeValues);
- auto endIndices = indexingMaps[en.index()].compose(*endLoopRangeValues);
- for (auto j : llvm::seq<unsigned>(0, en.value().getRank())) {
-
+ for (OpOperand *opOperand : linalgOp.getInputAndOutputOperands()) {
+ AffineMap indexingMap = linalgOp.getTiedIndexingMap(opOperand);
+ SmallVector<int64_t, 4> startIndices =
+ indexingMap.compose(startLoopRangeValues);
+ SmallVector<int64_t, 4> endIndices =
+ indexingMap.compose(*endLoopRangeValues);
+ ArrayRef<int64_t> shape = linalgOp.getShape(opOperand);
+ for (auto dim : llvm::seq<int64_t>(0, shape.size())) {
// Ignore dynamic dimension or the case that the dimension size is 0
- auto shapedDimSize = en.value().getDimSize(j);
- if (en.value().isDynamicDim(j) || shapedDimSize == 0)
+ if (ShapedType::isDynamic(shape[dim]) || shape[dim] == 0)
continue;
// The first index or last index should be the maximum or the minimum in
@@ -498,29 +499,32 @@ LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
// + d1 since it is not easy to handle the issues.
// Found the case that this solution can't check, for example, (d0, d1)
// -> (d1 - d0)
- auto inferredDimSize = std::max(startIndices[j], endIndices[j]) + 1;
- if (std::min(startIndices[j], endIndices[j]) < 0) {
+ int64_t inferredDimSize =
+ std::max(startIndices[dim], endIndices[dim]) + 1;
+ if (std::min(startIndices[dim], endIndices[dim]) < 0) {
std::string mapStr;
{
llvm::raw_string_ostream os(mapStr);
- os << indexingMaps[en.index()];
+ os << indexingMap;
}
- return linalgOp.emitError(
+ return op->emitOpError(
"unexpected result less than 0 at expression #")
- << j << " in " << mapStr;
+ << dim << " in " << mapStr;
}
- if (indexingMaps[en.index()].getResult(j).dyn_cast<AffineDimExpr>()) {
- if (inferredDimSize != shapedDimSize) {
- return linalgOp.emitOpError("inferred shaped operand #")
- << en.index() << " has shape's dimension #" << j << " to be "
- << inferredDimSize << ", but found " << shapedDimSize;
+ if (indexingMap.getResult(dim).dyn_cast<AffineDimExpr>()) {
+ if (inferredDimSize != shape[dim]) {
+ return op->emitOpError("inferred shaped operand #")
+ << opOperand->getOperandNumber()
+ << " has shape's dimension #" << dim << " to be "
+ << inferredDimSize << ", but found " << shape[dim];
}
} else {
- if (inferredDimSize > shapedDimSize) {
- return linalgOp.emitOpError("inferred shaped operand #")
- << en.index() << " has shape's dimension #" << j
+ if (inferredDimSize > shape[dim]) {
+ return op->emitOpError("inferred shaped operand #")
+ << opOperand->getOperandNumber()
+ << " has shape's dimension #" << dim
<< " to be greater than or equal to " << inferredDimSize
- << ", but found " << shapedDimSize;
+ << ", but found " << shape[dim];
}
}
}
More information about the Mlir-commits
mailing list