diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1139,7 +1139,7 @@ }]; let hasCustomAssemblyFormat = 1; - let hasVerifier = 1; + let hasRegionVerifier = 1; } def LLVM_GlobalCtorsOp : LLVM_Op<"mlir.global_ctors", [ diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -678,7 +678,7 @@ OptionalAttr:$memory_order); let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; - let hasVerifier = 1; + let hasRegionVerifier = 1; } def AtomicCaptureOp : OpenMP_Op<"atomic.capture", diff --git a/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td b/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td --- a/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td +++ b/mlir/include/mlir/Dialect/Tensor/IR/TensorOps.td @@ -407,7 +407,7 @@ ]; let hasCanonicalizer = 1; - let hasVerifier = 1; + let hasRegionVerifier = 1; } //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -2065,9 +2065,11 @@ // X op Y == Y op X def Commutative : NativeOpTrait<"IsCommutative">; // op op X == op X (unary) / X op X == X (binary) -def Idempotent : NativeOpTrait<"IsIdempotent">; +// FIXME: Idempotent should depend on SameOperandsAndResultType +def Idempotent : NativeOpTrait<"IsIdempotent">; // op op X == X -def Involution : NativeOpTrait<"IsInvolution">; +// FIXME: Involution should depend on SameOperandsAndResultType +def Involution : NativeOpTrait<"IsInvolution">; // Op behaves like a constant. def ConstantLike : NativeOpTrait<"ConstantLike">; // Op is isolated from above. @@ -2095,11 +2097,11 @@ // Op is elementwise on tensor/vector operands and results. def Elementwise : NativeOpTrait<"Elementwise">; // Elementwise op can be applied to scalars instead tensor/vector operands. -def Scalarizable : NativeOpTrait<"Scalarizable">; +def Scalarizable : NativeOpTrait<"Scalarizable", [Elementwise]>; // Elementwise op can be applied to all-vector operands. -def Vectorizable : NativeOpTrait<"Vectorizable">; +def Vectorizable : NativeOpTrait<"Vectorizable", [Elementwise]>; // Elementwise op can be applied to all-tensor operands. -def Tensorizable : NativeOpTrait<"Tensorizable">; +def Tensorizable : NativeOpTrait<"Tensorizable", [Elementwise]>; // Group together `Elementwise`, `Scalarizable`, `Vectorizable`, and // `Tensorizable` for convenience. diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h --- a/mlir/include/mlir/IR/OpDefinition.h +++ b/mlir/include/mlir/IR/OpDefinition.h @@ -920,7 +920,7 @@ /// The type of the operation used as the implicit terminator type. using ImplicitTerminatorOpT = TerminatorOpType; - static LogicalResult verifyTrait(Operation *op) { + static LogicalResult verifyRegionTrait(Operation *op) { if (failed(Base::verifyTrait(op))) return failure(); for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) { @@ -1218,7 +1218,7 @@ class IsIsolatedFromAbove : public TraitBase { public: - static LogicalResult verifyTrait(Operation *op) { + static LogicalResult verifyRegionTrait(Operation *op) { return impl::verifyIsIsolatedFromAbove(op); } }; @@ -1262,7 +1262,7 @@ class Impl : public TraitBase { public: static LogicalResult verifyTrait(Operation *op) { - if (llvm::isa(op->getParentOp())) + if (llvm::isa_and_nonnull(op->getParentOp())) return success(); return op->emitOpError() diff --git a/mlir/include/mlir/IR/SymbolTable.h b/mlir/include/mlir/IR/SymbolTable.h --- a/mlir/include/mlir/IR/SymbolTable.h +++ b/mlir/include/mlir/IR/SymbolTable.h @@ -337,7 +337,7 @@ template class SymbolTable : public TraitBase { public: - static LogicalResult verifyTrait(Operation *op) { + static LogicalResult verifyRegionTrait(Operation *op) { return ::mlir::detail::verifySymbolTable(op); } diff --git a/mlir/include/mlir/Interfaces/InferTypeOpInterface.td b/mlir/include/mlir/Interfaces/InferTypeOpInterface.td --- a/mlir/include/mlir/Interfaces/InferTypeOpInterface.td +++ b/mlir/include/mlir/Interfaces/InferTypeOpInterface.td @@ -64,6 +64,8 @@ >, ]; + // Inferring result types may need to access the region operations. + let verifyWithRegions=1; let verify = [{ return detail::verifyInferredResultTypes($_op); }]; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1771,7 +1771,7 @@ return false; } -LogicalResult GlobalOp::verify() { +LogicalResult GlobalOp::verifyRegions() { if (!LLVMPointerType::isValidElementType(getType())) return emitOpError( "expects type to be a valid element type for an LLVM pointer"); diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -1264,7 +1264,7 @@ } /// Verifier for AtomicUpdateOp -LogicalResult AtomicUpdateOp::verify() { +LogicalResult AtomicUpdateOp::verifyRegions() { if (auto mo = memory_order()) { if (*mo == ClauseMemoryOrderKind::acq_rel || *mo == ClauseMemoryOrderKind::acquire) { diff --git a/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp b/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp --- a/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp +++ b/mlir/lib/Dialect/Tensor/IR/TensorOps.cpp @@ -501,7 +501,7 @@ // GenerateOp //===----------------------------------------------------------------------===// -LogicalResult GenerateOp::verify() { +LogicalResult GenerateOp::verifyRegions() { // Ensure that the tensor type has as many dynamic dimensions as are specified // by the operands. RankedTensorType resultTy = getType().cast(); diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp --- a/mlir/lib/IR/Operation.cpp +++ b/mlir/lib/IR/Operation.cpp @@ -1088,11 +1088,11 @@ while (!pendingRegions.empty()) { for (Operation &op : pendingRegions.pop_back_val()->getOps()) { for (Value operand : op.getOperands()) { - // operand should be non-null here if the IR is well-formed. But - // we don't assert here as this function is called from the verifier - // and so could be called on invalid IR. - if (!operand) - return op.emitOpError("operation's operand is null"); + // operand should be non-null here. If this is called from the op + // verifier, then the region opreations are verified. If it's not from + // op verifier, then the caller should ensure all the region + // operations are well-formed. + assert(operand); // Check that any value that is used by an operation is defined in the // same region as either an operation result. diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -172,8 +172,7 @@ // ----- -// expected-error @+2 {{'llvm.mlir.global' op expects regions to end with 'llvm.return', found 'llvm.mlir.constant'}} -// expected-note @+1 {{in custom textual format, the absence of terminator implies 'llvm.return'}} +// expected-error @+2 {{block with no terminator, has %0 = llvm.mlir.constant(42 : i64) : i64}} llvm.mlir.global internal @g() : i64 { %c = llvm.mlir.constant(42 : i64) : i64 } diff --git a/mlir/test/Dialect/Linalg/invalid.mlir b/mlir/test/Dialect/Linalg/invalid.mlir --- a/mlir/test/Dialect/Linalg/invalid.mlir +++ b/mlir/test/Dialect/Linalg/invalid.mlir @@ -271,15 +271,14 @@ // ----- -func @generic(%arg0: memref) { - // expected-error @+2 {{op expects regions to end with 'linalg.yield', found 'arith.addf'}} - // expected-note @+1 {{in custom textual format, the absence of terminator implies 'linalg.yield'}} +func @generic(%arg0: memref) { + // expected-error @+6 {{block with no terminator, has %0 = arith.addf %arg1, %arg1 : f32}} linalg.generic { indexing_maps = [ affine_map<(i, j) -> (i, j)> ], iterator_types = ["parallel", "parallel"]} - outs(%arg0 : memref) { - ^bb(%0: i4) : - %1 = arith.addf %0, %0: i4 + outs(%arg0 : memref) { + ^bb(%0: f32) : + %1 = arith.addf %0, %0: f32 } return } diff --git a/mlir/test/Dialect/Tensor/invalid.mlir b/mlir/test/Dialect/Tensor/invalid.mlir --- a/mlir/test/Dialect/Tensor/invalid.mlir +++ b/mlir/test/Dialect/Tensor/invalid.mlir @@ -91,8 +91,7 @@ func @tensor.generate(%m : index, %n : index) -> tensor { - // expected-error @+2 {{op expects regions to end with 'tensor.yield', found 'std.return'}} - // expected-note @+1 {{in custom textual format, the absence of terminator implies 'tensor.yield'}} + // expected-error @+4 {{'std.return' op expects parent op 'builtin.func'}} %tnsr = tensor.generate %m, %n { ^bb0(%i : index, %j : index, %k : index): %elem = arith.constant 8.0 : f32 @@ -377,4 +376,4 @@ // expected-error@+1 {{must be integer/index/float type}} %w = tensor.splat %v : tensor<8xvector<8xf32>> return -} \ No newline at end of file +} diff --git a/mlir/test/IR/invalid.mlir b/mlir/test/IR/invalid.mlir --- a/mlir/test/IR/invalid.mlir +++ b/mlir/test/IR/invalid.mlir @@ -536,8 +536,7 @@ func @return_inside_loop() { affine.for %i = 1 to 100 { - // expected-error@-1 {{op expects regions to end with 'affine.yield', found 'std.return'}} - // expected-note@-2 {{in custom textual format, the absence of terminator implies}} + // expected-error@+1 {{op expects parent op 'builtin.func'}} return } return