diff --git a/mlir/test/mlir-tblgen/op-error.td b/mlir/test/mlir-tblgen/op-error.td --- a/mlir/test/mlir-tblgen/op-error.td +++ b/mlir/test/mlir-tblgen/op-error.td @@ -3,6 +3,7 @@ // RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s // RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s // RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s +// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s include "mlir/IR/OpBase.td" @@ -50,3 +51,11 @@ let results = (outs AnyTensor:$tensor, AnyTensor:$tensor); } #endif + +#ifdef ERROR6 +// ERROR6: error: op is using the same name for an operand and a result: 'tensor' +def OpWithDuplicatedArgResultNames : Op { + let arguments = (ins AnyTensor:$tensor); + let results = (outs AnyTensor:$tensor); +} +#endif diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp --- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp @@ -338,6 +338,9 @@ // Generate the type inference interface methods. void genTypeInterfaceMethods(); + // Verify the op invariants that emitters may rely on. + void assertInvariants(); + private: // The TableGen record for this op. // TODO: OpEmitter should not have a Record directly, @@ -472,6 +475,32 @@ } } +void OpEmitter::assertInvariants() { + SmallDenseSet operandNames; + for (int i : llvm::seq(0, op.getNumOperands())) { + const auto &operand = op.getOperand(i); + if (operand.name.empty()) + continue; + if (!operandNames.insert(operand.name).second) + PrintFatalError(op.getLoc(), "op has two operands with the same name: '" + + operand.name + "'"); + } + SmallDenseSet resultNames; + for (int i : llvm::seq(0, op.getNumResults())) { + const auto &result = op.getResult(i); + if (result.name.empty()) + continue; + if (!resultNames.insert(result.name).second) + PrintFatalError(op.getLoc(), "op has two results with the same name: '" + + result.name + "'"); + if (operandNames.contains(result.name)) + PrintFatalError( + op.getLoc(), + "op is using the same name for an operand and a result: '" + + result.name + "'"); + } +} + OpEmitter::OpEmitter(const Operator &op, const StaticVerifierFunctionEmitter &staticVerifierEmitter) : def(op.getDef()), op(op), @@ -479,6 +508,7 @@ staticVerifierEmitter(staticVerifierEmitter) { verifyCtx.withOp("(*this->getOperation())"); verifyCtx.addSubst("_ctxt", "this->getOperation()->getContext()"); + assertInvariants(); genTraits(); @@ -850,16 +880,10 @@ // Then we emit nicer named getter methods by redirecting to the "sink" getter // method. - // Keep track of the operand names to find duplicates. - SmallDenseSet operandNames; for (int i = 0; i != numOperands; ++i) { const auto &operand = op.getOperand(i); if (operand.name.empty()) continue; - if (!operandNames.insert(operand.name).second) - PrintFatalError(op.getLoc(), "op has two operands with the same name: '" + - operand.name + "'"); - if (operand.isOptional()) { m = opClass.addMethodAndPrune("::mlir::Value", operand.name); m->body() @@ -992,15 +1016,10 @@ m->body() << formatv(valueRangeReturnCode, "getOperation()->result_begin()", "getODSResultIndexAndLength(index)"); - SmallDenseSet resultNames; for (int i = 0; i != numResults; ++i) { const auto &result = op.getResult(i); if (result.name.empty()) continue; - if (!resultNames.insert(result.name).second) - PrintFatalError(op.getLoc(), "op has two results with the same name: '" + - result.name + "'"); - if (result.isOptional()) { m = opClass.addMethodAndPrune("::mlir::Value", result.name); m->body()