[mlir][Utils] Add VerificationUtils (NFC) (#174336)
Introduces `VerificationUtils` to consolidate common operation verification patterns in MLIR. This initial implementation provides `verifyDynamicDimensionCount()` to reduce code duplication across dialect verifiers. This is an NFC (No Functional Change) refactoring that improves code maintainability by extracting reusable verification logic into a shared utility.
This commit is contained in:
parent
ab34189878
commit
e289b2e765
11 changed files with 82 additions and 31 deletions
32
mlir/include/mlir/Dialect/Utils/VerificationUtils.h
Normal file
32
mlir/include/mlir/Dialect/Utils/VerificationUtils.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//===- VerificationUtils.h - Common verification utilities ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header file defines common verification utilities that can be shared
|
||||
// across multiple MLIR dialects. These utilities help reduce code duplication
|
||||
// for common verification patterns.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_DIALECT_UTILS_VERIFICATIONUTILS_H
|
||||
#define MLIR_DIALECT_UTILS_VERIFICATIONUTILS_H
|
||||
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/Support/LLVM.h"
|
||||
|
||||
namespace mlir {
|
||||
|
||||
/// Verify that the number of dynamic size operands matches the number of
|
||||
/// dynamic dimensions in the shaped type. Returns failure and emits an error
|
||||
/// if the counts don't match.
|
||||
LogicalResult verifyDynamicDimensionCount(Operation *op, ShapedType type,
|
||||
ValueRange dynamicSizes);
|
||||
|
||||
} // namespace mlir
|
||||
|
||||
#endif // MLIR_DIALECT_UTILS_VERIFICATIONUTILS_H
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
#include "mlir/Dialect/Func/IR/FuncOps.h"
|
||||
#include "mlir/Dialect/MemRef/IR/MemRef.h"
|
||||
#include "mlir/Dialect/Tensor/IR/Tensor.h"
|
||||
#include "mlir/Dialect/Utils/VerificationUtils.h"
|
||||
#include "mlir/IR/Matchers.h"
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -251,9 +252,9 @@ AllocTensorOp::getBufferType(Value value, const BufferizationOptions &options,
|
|||
LogicalResult AllocTensorOp::verify() {
|
||||
if (getCopy() && !getDynamicSizes().empty())
|
||||
return emitError("dynamic sizes not needed when copying a tensor");
|
||||
if (!getCopy() && getType().getNumDynamicDims() != getDynamicSizes().size())
|
||||
return emitError("expected ")
|
||||
<< getType().getNumDynamicDims() << " dynamic sizes";
|
||||
if (!getCopy() && failed(verifyDynamicDimensionCount(
|
||||
getOperation(), getType(), getDynamicSizes())))
|
||||
return failure();
|
||||
if (getCopy() && getCopy().getType() != getType())
|
||||
return emitError("expected that `copy` and return type match");
|
||||
return success();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
|
||||
#include "mlir/Dialect/Math/IR/Math.h"
|
||||
#include "mlir/Dialect/MemRef/IR/MemRef.h"
|
||||
#include "mlir/Dialect/Utils/VerificationUtils.h"
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
|
|
@ -2171,9 +2172,9 @@ void WaitOp::getCanonicalizationPatterns(RewritePatternSet &results,
|
|||
LogicalResult AllocOp::verify() {
|
||||
auto memRefType = llvm::cast<MemRefType>(getMemref().getType());
|
||||
|
||||
if (getDynamicSizes().size() != memRefType.getNumDynamicDims())
|
||||
return emitOpError("dimension operand count does not equal memref "
|
||||
"dynamic dimension count");
|
||||
if (failed(verifyDynamicDimensionCount(getOperation(), memRefType,
|
||||
getDynamicSizes())))
|
||||
return failure();
|
||||
|
||||
unsigned numSymbols = 0;
|
||||
if (!memRefType.getLayout().isIdentity())
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "mlir/Dialect/Arith/Utils/Utils.h"
|
||||
#include "mlir/Dialect/MemRef/IR/MemRef.h"
|
||||
#include "mlir/Dialect/Utils/StaticValueUtils.h"
|
||||
#include "mlir/Dialect/Utils/VerificationUtils.h"
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
|
|
@ -192,9 +193,8 @@ static LogicalResult verifyAllocLikeOp(AllocLikeOp op) {
|
|||
if (!memRefType)
|
||||
return op.emitOpError("result must be a memref");
|
||||
|
||||
if (op.getDynamicSizes().size() != memRefType.getNumDynamicDims())
|
||||
return op.emitOpError("dimension operand count does not equal memref "
|
||||
"dynamic dimension count");
|
||||
if (failed(verifyDynamicDimensionCount(op, memRefType, op.getDynamicSizes())))
|
||||
return failure();
|
||||
|
||||
unsigned numSymbols = 0;
|
||||
if (!memRefType.getLayout().isIdentity())
|
||||
|
|
@ -3735,9 +3735,8 @@ LogicalResult ViewOp::verify() {
|
|||
<< baseType << " and view memref type " << viewType;
|
||||
|
||||
// Verify that we have the correct number of sizes for the result type.
|
||||
unsigned numDynamicDims = viewType.getNumDynamicDims();
|
||||
if (getSizes().size() != numDynamicDims)
|
||||
return emitError("incorrect number of size operands for type ") << viewType;
|
||||
if (failed(verifyDynamicDimensionCount(getOperation(), viewType, getSizes())))
|
||||
return failure();
|
||||
|
||||
return success();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "mlir/Dialect/Utils/IndexingUtils.h"
|
||||
#include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
|
||||
#include "mlir/Dialect/Utils/StaticValueUtils.h"
|
||||
#include "mlir/Dialect/Utils/VerificationUtils.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinAttributeInterfaces.h"
|
||||
#include "mlir/IR/BuiltinTypeInterfaces.h"
|
||||
|
|
@ -1075,11 +1076,8 @@ void EmptyOp::build(OpBuilder &builder, OperationState &result,
|
|||
}
|
||||
|
||||
LogicalResult EmptyOp::verify() {
|
||||
if (getType().getNumDynamicDims() != getDynamicSizes().size())
|
||||
return emitOpError("incorrect number of dynamic sizes, has ")
|
||||
<< getDynamicSizes().size() << ", expected "
|
||||
<< getType().getNumDynamicDims();
|
||||
return success();
|
||||
return verifyDynamicDimensionCount(getOperation(), getType(),
|
||||
getDynamicSizes());
|
||||
}
|
||||
|
||||
LogicalResult
|
||||
|
|
@ -1666,9 +1664,9 @@ LogicalResult GenerateOp::verify() {
|
|||
// Ensure that the tensor type has as many dynamic dimensions as are
|
||||
// specified by the operands.
|
||||
RankedTensorType resultType = llvm::cast<RankedTensorType>(getType());
|
||||
if (getNumOperands() != resultType.getNumDynamicDims())
|
||||
return emitError("must have as many index operands as dynamic extents "
|
||||
"in the result type");
|
||||
if (failed(verifyDynamicDimensionCount(getOperation(), resultType,
|
||||
getOperands())))
|
||||
return failure();
|
||||
return success();
|
||||
}
|
||||
|
||||
|
|
@ -4039,11 +4037,8 @@ void SplatOp::getAsmResultNames(
|
|||
}
|
||||
|
||||
LogicalResult SplatOp::verify() {
|
||||
if (getType().getNumDynamicDims() != getDynamicSizes().size())
|
||||
return emitOpError("incorrect number of dynamic sizes, has ")
|
||||
<< getDynamicSizes().size() << ", expected "
|
||||
<< getType().getNumDynamicDims();
|
||||
return success();
|
||||
return verifyDynamicDimensionCount(getOperation(), getType(),
|
||||
getDynamicSizes());
|
||||
}
|
||||
|
||||
LogicalResult
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ add_mlir_library(MLIRDialectUtils
|
|||
ReshapeOpsUtils.cpp
|
||||
StructuredOpsUtils.cpp
|
||||
StaticValueUtils.cpp
|
||||
VerificationUtils.cpp
|
||||
|
||||
DEPENDS
|
||||
MLIRDialectUtilsIncGen
|
||||
|
|
|
|||
22
mlir/lib/Dialect/Utils/VerificationUtils.cpp
Normal file
22
mlir/lib/Dialect/Utils/VerificationUtils.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//===- VerificationUtils.cpp - Common verification utilities --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Dialect/Utils/VerificationUtils.h"
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
LogicalResult mlir::verifyDynamicDimensionCount(Operation *op, ShapedType type,
|
||||
ValueRange dynamicSizes) {
|
||||
int64_t expectedCount = type.getNumDynamicDims();
|
||||
int64_t actualCount = dynamicSizes.size();
|
||||
if (expectedCount != actualCount) {
|
||||
return op->emitOpError("incorrect number of dynamic sizes, has ")
|
||||
<< actualCount << ", expected " << expectedCount;
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
func.func @alloc_tensor_missing_dims(%arg0: index)
|
||||
{
|
||||
// expected-error @+1 {{expected 2 dynamic sizes}}
|
||||
// expected-error @+1 {{incorrect number of dynamic sizes, has 1, expected 2}}
|
||||
%0 = bufferization.alloc_tensor(%arg0) : tensor<4x?x?x5xf32>
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@ func.func @alloc() {
|
|||
// Number of dynamic dimension operand count greater than memref dynamic dimension count.
|
||||
func.func @alloc() {
|
||||
%0 = arith.constant 7 : index
|
||||
// expected-error@+1 {{dimension operand count does not equal memref dynamic dimension count}}
|
||||
// expected-error@+1 {{incorrect number of dynamic sizes, has 2, expected 1}}
|
||||
%1 = gpu.alloc(%0, %0) : memref<2x?xf32, 1>
|
||||
return
|
||||
}
|
||||
|
|
@ -787,7 +787,7 @@ func.func @alloc() {
|
|||
// Number of dynamic dimension operand count less than memref dynamic dimension count.
|
||||
func.func @alloc() {
|
||||
%0 = arith.constant 7 : index
|
||||
// expected-error@+1 {{dimension operand count does not equal memref dynamic dimension count}}
|
||||
// expected-error@+1 {{incorrect number of dynamic sizes, has 1, expected 2}}
|
||||
%1 = gpu.alloc(%0) : memref<2x?x?xf32, 1>
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ func.func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
|
|||
|
||||
func.func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
|
||||
%0 = memref.alloc() : memref<2048xi8>
|
||||
// expected-error@+1 {{incorrect number of size operands for type}}
|
||||
// expected-error@+1 {{incorrect number of dynamic sizes, has 1, expected 2}}
|
||||
%1 = memref.view %0[%arg2][%arg0]
|
||||
: memref<2048xi8> to memref<?x?xf32>
|
||||
return
|
||||
|
|
@ -927,7 +927,7 @@ func.func @bad_alloc_wrong_dynamic_dim_count() {
|
|||
^bb0:
|
||||
%0 = arith.constant 7 : index
|
||||
// Test alloc with wrong number of dynamic dimensions.
|
||||
// expected-error@+1 {{dimension operand count does not equal memref dynamic dimension count}}
|
||||
// expected-error@+1 {{incorrect number of dynamic sizes, has 1, expected 0}}
|
||||
%1 = memref.alloc(%0)[%0] : memref<2x4xf32, affine_map<(d0, d1)[s0] -> ((d0 + s0), d1)>, 1>
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ func.func @tensor.from_elements_wrong_elements_count() {
|
|||
|
||||
func.func @tensor.generate(%m : index)
|
||||
-> tensor<?x3x?xf32> {
|
||||
// expected-error @+1 {{must have as many index operands as dynamic extents in the result type}}
|
||||
// expected-error @+1 {{incorrect number of dynamic sizes, has 1, expected 2}}
|
||||
%tnsr = tensor.generate %m {
|
||||
^bb0(%i : index, %j : index, %k : index):
|
||||
%elem = arith.constant 8.0 : f32
|
||||
|
|
|
|||
Loading…
Reference in a new issue