[mlir][ods] Add Deprecate helper
Add method to tag classes/defs as deprecated. Previously deprecations were only verbally communicated and folks didn't have an active warning while building about impending removal. Add mechanism to tag defs as deprecated to allow warning users. This doesn't change any policy, it just moves deprecation warnings from comments to something more user visible. Differential Revision: https://reviews.llvm.org/D122164
This commit is contained in:
@@ -1526,6 +1526,19 @@ mlir-tblgen --gen-op-interface-doc -I /path/to/mlir/include /path/to/input/td/fi
|
||||
|
||||
## Appendix
|
||||
|
||||
### Reporting deprecation
|
||||
|
||||
Classes/defs can be marked as deprecated by using the `Deprecate` helper class,
|
||||
e.g.,
|
||||
|
||||
```td
|
||||
def OpTraitA : NativeOpTrait<"OpTraitA">, Deprecated<"use `bar` instead">;
|
||||
```
|
||||
|
||||
would result in marking `OpTraitA` as deprecated and mlir-tblgen can emit a
|
||||
warning (default) or error (depending on `-on-deprecated` flag) to make
|
||||
deprecated state known.
|
||||
|
||||
### Requirements and existing mechanisms analysis
|
||||
|
||||
The op description should be as declarative as possible to allow a wide range of
|
||||
|
||||
@@ -38,6 +38,12 @@ class StrFunc<string r> {
|
||||
string result = r;
|
||||
}
|
||||
|
||||
// Helper for marking deprecated classes or defs. To mark a def as deprecated,
|
||||
// mix in the `Deprecate` class with a reason.
|
||||
class Deprecated<string reason> {
|
||||
string odsDeprecated = reason;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Predicate definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
15
mlir/test/mlir-tblgen/deprecation.td
Normal file
15
mlir/test/mlir-tblgen/deprecation.td
Normal file
@@ -0,0 +1,15 @@
|
||||
// RUN: not mlir-tblgen -on-deprecated=error -gen-op-decls -I %S/../../include -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
|
||||
|
||||
include "mlir/IR/OpBase.td"
|
||||
|
||||
def Test_Dialect : Dialect {
|
||||
let name = "test_dialect";
|
||||
}
|
||||
|
||||
#ifdef ERROR1
|
||||
def OpTraitA : NativeOpTrait<"OpTraitA">, Deprecated<"use `bar` instead">;
|
||||
|
||||
// ERROR1: warning: Using deprecated def `OpTraitA`
|
||||
// ERROR1: use `bar` instead
|
||||
def OpTraitWithoutDependentTrait : Op<Test_Dialect, "default_value", [OpTraitA]> {}
|
||||
#endif
|
||||
@@ -26,6 +26,15 @@
|
||||
using namespace llvm;
|
||||
using namespace mlir;
|
||||
|
||||
enum DeprecatedAction { None, Warn, Error };
|
||||
llvm::cl::opt<DeprecatedAction> actionOnDeprecated(
|
||||
"on-deprecated", llvm::cl::init(Warn),
|
||||
llvm::cl::desc("Action to perform on deprecated def"),
|
||||
llvm::cl::values(clEnumValN(DeprecatedAction::None, "none", "No action"),
|
||||
clEnumValN(DeprecatedAction::Warn, "warn", "Warn on use"),
|
||||
clEnumValN(DeprecatedAction::Error, "error",
|
||||
"Error on use")));
|
||||
|
||||
static llvm::ManagedStatic<std::vector<GenInfo>> generatorRegistry;
|
||||
|
||||
mlir::GenRegistration::GenRegistration(StringRef arg, StringRef description,
|
||||
@@ -62,9 +71,80 @@ GenRegistration printRecords("print-records", "Print all records to stdout",
|
||||
// Generator to invoke.
|
||||
const mlir::GenInfo *generator;
|
||||
|
||||
// Returns if there is a use of `init` in `record`.
|
||||
bool findUse(Record &record, Init *init,
|
||||
llvm::DenseMap<Record *, bool> &known) {
|
||||
auto it = known.find(&record);
|
||||
if (it != known.end())
|
||||
return it->second;
|
||||
|
||||
auto memoize = [&](bool val) {
|
||||
known[&record] = val;
|
||||
return val;
|
||||
};
|
||||
|
||||
for (const RecordVal &val : record.getValues()) {
|
||||
Init *valInit = val.getValue();
|
||||
if (valInit == init)
|
||||
return true;
|
||||
if (auto *di = dyn_cast<DefInit>(valInit)) {
|
||||
if (findUse(*di->getDef(), init, known))
|
||||
return memoize(true);
|
||||
} else if (auto *di = dyn_cast<DagInit>(valInit)) {
|
||||
for (Init *arg : di->getArgs())
|
||||
if (auto *di = dyn_cast<DefInit>(arg))
|
||||
if (findUse(*di->getDef(), init, known))
|
||||
return memoize(true);
|
||||
} else if (ListInit *li = dyn_cast<ListInit>(valInit)) {
|
||||
for (Init *jt : li->getValues())
|
||||
if (jt == init)
|
||||
return memoize(true);
|
||||
}
|
||||
}
|
||||
return memoize(false);
|
||||
}
|
||||
|
||||
void warnOfDeprecatedUses(RecordKeeper &records) {
|
||||
// This performs a direct check for any def marked as deprecated and then
|
||||
// finds all uses of deprecated def. Deprecated defs are not expected to be
|
||||
// either numerous or long lived.
|
||||
bool deprecatedDefsFounds = false;
|
||||
for (auto &it : records.getDefs()) {
|
||||
const RecordVal *r = it.second->getValue("odsDeprecated");
|
||||
if (!r || !r->getValue())
|
||||
continue;
|
||||
|
||||
llvm::DenseMap<Record *, bool> hasUse;
|
||||
if (auto *si = dyn_cast<StringInit>(r->getValue())) {
|
||||
for (auto &jt : records.getDefs()) {
|
||||
// Skip anonymous defs.
|
||||
if (jt.second->isAnonymous())
|
||||
continue;
|
||||
// Skip all outside main file to avoid flagging redundantly.
|
||||
unsigned buf =
|
||||
SrcMgr.FindBufferContainingLoc(jt.second->getLoc().front());
|
||||
if (buf != SrcMgr.getMainFileID())
|
||||
continue;
|
||||
|
||||
if (findUse(*jt.second, it.second->getDefInit(), hasUse)) {
|
||||
PrintWarning(jt.second->getLoc(),
|
||||
"Using deprecated def `" + it.first + "`");
|
||||
PrintNote(si->getAsUnquotedString());
|
||||
deprecatedDefsFounds = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deprecatedDefsFounds && actionOnDeprecated == DeprecatedAction::Error)
|
||||
PrintFatalNote("Error'ing out due to deprecated defs");
|
||||
}
|
||||
|
||||
// TableGenMain requires a function pointer so this function is passed in which
|
||||
// simply wraps the call to the generator.
|
||||
static bool mlirTableGenMain(raw_ostream &os, RecordKeeper &records) {
|
||||
if (actionOnDeprecated != DeprecatedAction::None)
|
||||
warnOfDeprecatedUses(records);
|
||||
|
||||
if (!generator) {
|
||||
os << records;
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user