1//===- MlirTblgenMain.cpp - MLIR Tablegen Driver main -----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Main entry function for mlir-tblgen for when built as standalone binary.
10//
11//===----------------------------------------------------------------------===//
12
13#include "mlir/Tools/mlir-tblgen/MlirTblgenMain.h"
14
15#include "mlir/TableGen/GenInfo.h"
16#include "mlir/TableGen/GenNameParser.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/FormatVariadic.h"
19#include "llvm/Support/InitLLVM.h"
20#include "llvm/Support/Signals.h"
21#include "llvm/TableGen/Error.h"
22#include "llvm/TableGen/Main.h"
23#include "llvm/TableGen/Record.h"
24
25using namespace mlir;
26using namespace llvm;
27
28enum DeprecatedAction { None, Warn, Error };
29
30static DeprecatedAction actionOnDeprecatedValue;
31
32// Returns if there is a use of `deprecatedInit` in `field`.
33static bool findUse(Init *field, Init *deprecatedInit,
34 llvm::DenseMap<Init *, bool> &known) {
35 if (field == deprecatedInit)
36 return true;
37
38 auto it = known.find(Val: field);
39 if (it != known.end())
40 return it->second;
41
42 auto memoize = [&](bool val) {
43 known[field] = val;
44 return val;
45 };
46
47 if (auto *defInit = dyn_cast<DefInit>(Val: field)) {
48 // Only recurse into defs if they are anonymous.
49 // Non-anonymous defs are handled by the main loop, with a proper
50 // deprecation warning for each. Returning true here, would cause
51 // all users of a def to also emit a deprecation warning.
52 if (!defInit->getDef()->isAnonymous())
53 // Purposefully not memoize as to not include every def use in the map.
54 // This is also a trivial case we return false for in constant time.
55 return false;
56
57 return memoize(
58 llvm::any_of(Range: defInit->getDef()->getValues(), P: [&](const RecordVal &val) {
59 return findUse(field: val.getValue(), deprecatedInit, known);
60 }));
61 }
62
63 if (auto *dagInit = dyn_cast<DagInit>(Val: field)) {
64 if (findUse(field: dagInit->getOperator(), deprecatedInit, known))
65 return memoize(true);
66
67 return memoize(llvm::any_of(Range: dagInit->getArgs(), P: [&](Init *arg) {
68 return findUse(field: arg, deprecatedInit, known);
69 }));
70 }
71
72 if (ListInit *li = dyn_cast<ListInit>(Val: field)) {
73 return memoize(llvm::any_of(Range: li->getValues(), P: [&](Init *jt) {
74 return findUse(field: jt, deprecatedInit, known);
75 }));
76 }
77
78 // Purposefully don't use memoize here. There is no need to cache the result
79 // for every kind of init (e.g. BitInit or StringInit), which will always
80 // return false. Doing so would grow the DenseMap to include almost every Init
81 // within the main file.
82 return false;
83}
84
85// Returns if there is a use of `deprecatedInit` in `record`.
86static bool findUse(Record &record, Init *deprecatedInit,
87 llvm::DenseMap<Init *, bool> &known) {
88 return llvm::any_of(Range: record.getValues(), P: [&](const RecordVal &val) {
89 return findUse(field: val.getValue(), deprecatedInit, known);
90 });
91}
92
93static void warnOfDeprecatedUses(RecordKeeper &records) {
94 // This performs a direct check for any def marked as deprecated and then
95 // finds all uses of deprecated def. Deprecated defs are not expected to be
96 // either numerous or long lived.
97 bool deprecatedDefsFounds = false;
98 for (auto &it : records.getDefs()) {
99 const RecordVal *r = it.second->getValue(Name: "odsDeprecated");
100 if (!r || !r->getValue())
101 continue;
102
103 llvm::DenseMap<Init *, bool> hasUse;
104 if (auto *si = dyn_cast<StringInit>(Val: r->getValue())) {
105 for (auto &jt : records.getDefs()) {
106 // Skip anonymous defs.
107 if (jt.second->isAnonymous())
108 continue;
109
110 if (findUse(record&: *jt.second, deprecatedInit: it.second->getDefInit(), known&: hasUse)) {
111 PrintWarning(WarningLoc: jt.second->getLoc(),
112 Msg: "Using deprecated def `" + it.first + "`");
113 PrintNote(Msg: si->getAsUnquotedString());
114 deprecatedDefsFounds = true;
115 }
116 }
117 }
118 }
119 if (deprecatedDefsFounds &&
120 actionOnDeprecatedValue == DeprecatedAction::Error)
121 PrintFatalNote(Msg: "Error'ing out due to deprecated defs");
122}
123
124// Generator to invoke.
125static const mlir::GenInfo *generator;
126
127// TableGenMain requires a function pointer so this function is passed in which
128// simply wraps the call to the generator.
129static bool mlirTableGenMain(raw_ostream &os, RecordKeeper &records) {
130 if (actionOnDeprecatedValue != DeprecatedAction::None)
131 warnOfDeprecatedUses(records);
132
133 if (!generator) {
134 os << records;
135 return false;
136 }
137 return generator->invoke(recordKeeper: records, os);
138}
139
140int mlir::MlirTblgenMain(int argc, char **argv) {
141
142 llvm::InitLLVM y(argc, argv);
143
144 llvm::cl::opt<DeprecatedAction, true> actionOnDeprecated(
145 "on-deprecated", llvm::cl::desc("Action to perform on deprecated def"),
146 llvm::cl::values(
147 clEnumValN(DeprecatedAction::None, "none", "No action"),
148 clEnumValN(DeprecatedAction::Warn, "warn", "Warn on use"),
149 clEnumValN(DeprecatedAction::Error, "error", "Error on use")),
150 cl::location(L&: actionOnDeprecatedValue), llvm::cl::init(Val: Warn));
151
152 llvm::cl::opt<const mlir::GenInfo *, true, mlir::GenNameParser> generator(
153 "", llvm::cl::desc("Generator to run"), cl::location(L&: ::generator));
154
155 cl::ParseCommandLineOptions(argc, argv);
156
157 return TableGenMain(argv0: argv[0], MainFn: &mlirTableGenMain);
158}
159

source code of mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp