diff --git a/mlir/docs/DefiningDialects/Operations.md b/mlir/docs/DefiningDialects/Operations.md --- a/mlir/docs/DefiningDialects/Operations.md +++ b/mlir/docs/DefiningDialects/Operations.md @@ -1571,7 +1571,7 @@ ## Appendix -### Reporting deprecation +### Reporting deprecation in TableGen Classes/defs can be marked as deprecated by using the `Deprecate` helper class, e.g., @@ -1584,6 +1584,29 @@ warning (default) or error (depending on `-on-deprecated` flag) to make deprecated state known. +### Reporting deprecation in C++ + +TableGen generated C++ entities, such as classes, functions or methods, can be +marked as deprecated using the `CppDeprecated` mixin: + +```tablegen +def MyOp : Op, CppDeprecated<"use 'your.op' instead">; +``` + +This differs to the deprecation mechanic for TableGen, in that no warning is +emitted by mlir-tblgen. Rather, a warning with the given reason is emitted by +the C++ compiler on use of the given entity. + +To allow more convenient syntax, helper classes exist for TableGen classes +which are commonly used as anonymous definitions. These currently include: + +* `DeprecatedOpBuilder`: Can be used in place of `OpBuilder` with the same + arguments except taking the reason as first argument, e.g. + `DeprecatedOpBuilder<"use 'build' with foo instead", (ins "int":$bar)>` + +Note: Support for the `CppDeprecated` mechanism has to be implemented by +every code generator separately. + ### Requirements and existing mechanisms analysis The op description should be as declarative as possible to allow a wide range of diff --git a/mlir/include/mlir/IR/DialectBase.td b/mlir/include/mlir/IR/DialectBase.td --- a/mlir/include/mlir/IR/DialectBase.td +++ b/mlir/include/mlir/IR/DialectBase.td @@ -13,12 +13,24 @@ #ifndef DIALECTBASE_TD #define DIALECTBASE_TD -// Helper for marking deprecated classes or defs. To mark a def as deprecated, -// mix in the `Deprecate` class with a reason. +// Helper for marking deprecated classes or defs in TableGen. To mark a def as +// deprecated, mix in the `Deprecate` class with a reason. +// Usage of a deprecated def within TableGen will cause a warning with the +// given message. class Deprecated { string odsDeprecated = reason; } +// Helper for marking entities in ODS generated C++ as deprecated. +// Usage of such an entity from C++ code will cause a warning being emitted by +// the C++ compiler with the given message. +// +// Note: Support has to be implemented by the code generator of a given +// entity. +class CppDeprecated { + string odsCppDeprecated = reason; +} + //===----------------------------------------------------------------------===// // Dialect definitions //===----------------------------------------------------------------------===// 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 @@ -2235,6 +2235,12 @@ code body = b; } +// OpBuilder like the above, but the emitted 'build' method is marked as +// deprecated in C++. Use of it will emit a warning by the C++ compiler +// with the given reason. +class DeprecatedOpBuilder + : OpBuilder, CppDeprecated; + // A base decorator class that may optionally be added to OpVariables. class OpVariableDecorator; diff --git a/mlir/include/mlir/TableGen/Builder.h b/mlir/include/mlir/TableGen/Builder.h --- a/mlir/include/mlir/TableGen/Builder.h +++ b/mlir/include/mlir/TableGen/Builder.h @@ -70,6 +70,10 @@ /// Return an optional string containing the body of the builder. std::optional getBody() const; + /// Return the deprecation message of the builder. + /// Empty optional if the builder is not deprecated. + std::optional getDeprecatedMessage() const; + protected: /// The TableGen definition of this builder. const llvm::Record *def; diff --git a/mlir/include/mlir/TableGen/Class.h b/mlir/include/mlir/TableGen/Class.h --- a/mlir/include/mlir/TableGen/Class.h +++ b/mlir/include/mlir/TableGen/Class.h @@ -329,6 +329,11 @@ /// Get the method body. MethodBody &body() { return methodBody; } + /// Sets or removes the deprecation message of the method. + void setDeprecated(std::optional message) { + this->deprecationMessage = message; + } + /// Returns true if this is a static method. bool isStatic() const { return properties & Static; } @@ -369,6 +374,8 @@ MethodSignature methodSignature; /// The body of the method, if it has one. MethodBody methodBody; + /// Deprecation message if the method is deprecated. + std::optional deprecationMessage; }; /// This enum describes C++ inheritance visibility. diff --git a/mlir/lib/TableGen/Builder.cpp b/mlir/lib/TableGen/Builder.cpp --- a/mlir/lib/TableGen/Builder.cpp +++ b/mlir/lib/TableGen/Builder.cpp @@ -81,3 +81,9 @@ std::optional body = def->getValueAsOptionalString("body"); return body && !body->empty() ? body : std::nullopt; } + +std::optional Builder::getDeprecatedMessage() const { + std::optional message = + def->getValueAsOptionalString("odsCppDeprecated"); + return message && !message->empty() ? message : std::nullopt; +} diff --git a/mlir/lib/TableGen/Class.cpp b/mlir/lib/TableGen/Class.cpp --- a/mlir/lib/TableGen/Class.cpp +++ b/mlir/lib/TableGen/Class.cpp @@ -114,6 +114,11 @@ //===----------------------------------------------------------------------===// void Method::writeDeclTo(raw_indented_ostream &os) const { + if (deprecationMessage) { + os << "[[deprecated(\""; + os.write_escaped(*deprecationMessage); + os << "\")]]\n"; + } if (isStatic()) os << "static "; if (properties & ConstexprValue) diff --git a/mlir/test/mlir-tblgen/op-decl-and-defs.td b/mlir/test/mlir-tblgen/op-decl-and-defs.td --- a/mlir/test/mlir-tblgen/op-decl-and-defs.td +++ b/mlir/test/mlir-tblgen/op-decl-and-defs.td @@ -38,7 +38,9 @@ VariadicRegion:$someRegions ); let builders = [OpBuilder<(ins "Value":$val)>, - OpBuilder<(ins CArg<"int", "0">:$integer)>]; + OpBuilder<(ins CArg<"int", "0">:$integer)>, + DeprecatedOpBuilder<"the deprecation message", + (ins "float":$something)>]; let hasCustomAssemblyFormat = 1; let hasCanonicalizer = 1; @@ -107,6 +109,8 @@ // CHECK: ::mlir::Attribute removeSomeAttr2Attr(); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, Value val); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, int integer = 0); +// CHECK{LITERAL}: [[deprecated("the deprecation message")]] +// CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, float something); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type r, ::mlir::TypeRange s, ::mlir::Value a, ::mlir::ValueRange b, ::mlir::IntegerAttr attr1, /*optional*/::mlir::FloatAttr some_attr2, unsigned someRegionsCount) // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::Value a, ::mlir::ValueRange b, ::mlir::IntegerAttr attr1, /*optional*/::mlir::FloatAttr some_attr2, unsigned someRegionsCount); // CHECK: static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type r, ::mlir::TypeRange s, ::mlir::Value a, ::mlir::ValueRange b, uint32_t attr1, /*optional*/::mlir::FloatAttr some_attr2, unsigned someRegionsCount) 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 @@ -1965,6 +1965,9 @@ if (body) ERROR_IF_PRUNED(method, "build", op); + if (method) + method->setDeprecated(builder.getDeprecatedMessage()); + FmtContext fctx; fctx.withBuilder(odsBuilder); fctx.addSubst("_state", builderOpState);