1 //===- mlir-tblgen.cpp - Top-Level TableGen implementation for MLIR -------===//
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 // This file contains the main function for MLIR's TableGen.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "mlir/TableGen/GenInfo.h"
14 #include "mlir/TableGen/GenNameParser.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Support/FormatVariadic.h"
18 #include "llvm/Support/InitLLVM.h"
19 #include "llvm/Support/ManagedStatic.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 #include "llvm/TableGen/TableGenBackend.h"
25
26 using namespace llvm;
27 using namespace mlir;
28
29 enum DeprecatedAction { None, Warn, Error };
30 llvm::cl::opt<DeprecatedAction> actionOnDeprecated(
31 "on-deprecated", llvm::cl::init(Warn),
32 llvm::cl::desc("Action to perform on deprecated def"),
33 llvm::cl::values(clEnumValN(DeprecatedAction::None, "none", "No action"),
34 clEnumValN(DeprecatedAction::Warn, "warn", "Warn on use"),
35 clEnumValN(DeprecatedAction::Error, "error",
36 "Error on use")));
37
38 static llvm::ManagedStatic<std::vector<GenInfo>> generatorRegistry;
39
GenRegistration(StringRef arg,StringRef description,const GenFunction & function)40 mlir::GenRegistration::GenRegistration(StringRef arg, StringRef description,
41 const GenFunction &function) {
42 generatorRegistry->emplace_back(arg, description, function);
43 }
44
GenNameParser(llvm::cl::Option & opt)45 GenNameParser::GenNameParser(llvm::cl::Option &opt)
46 : llvm::cl::parser<const GenInfo *>(opt) {
47 for (const auto &kv : *generatorRegistry) {
48 addLiteralOption(kv.getGenArgument(), &kv, kv.getGenDescription());
49 }
50 }
51
printOptionInfo(const llvm::cl::Option & o,size_t globalWidth) const52 void GenNameParser::printOptionInfo(const llvm::cl::Option &o,
53 size_t globalWidth) const {
54 GenNameParser *tp = const_cast<GenNameParser *>(this);
55 llvm::array_pod_sort(tp->Values.begin(), tp->Values.end(),
56 [](const GenNameParser::OptionInfo *vT1,
57 const GenNameParser::OptionInfo *vT2) {
58 return vT1->Name.compare(vT2->Name);
59 });
60 using llvm::cl::parser;
61 parser<const GenInfo *>::printOptionInfo(o, globalWidth);
62 }
63
64 // Generator that prints records.
65 GenRegistration printRecords("print-records", "Print all records to stdout",
__anon70db4cfc0202(const RecordKeeper &records, raw_ostream &os) 66 [](const RecordKeeper &records, raw_ostream &os) {
67 os << records;
68 return false;
69 });
70
71 // Generator to invoke.
72 const mlir::GenInfo *generator;
73
74 // Returns if there is a use of `init` in `record`.
findUse(Record & record,Init * init,llvm::DenseMap<Record *,bool> & known)75 bool findUse(Record &record, Init *init,
76 llvm::DenseMap<Record *, bool> &known) {
77 auto it = known.find(&record);
78 if (it != known.end())
79 return it->second;
80
81 auto memoize = [&](bool val) {
82 known[&record] = val;
83 return val;
84 };
85
86 for (const RecordVal &val : record.getValues()) {
87 Init *valInit = val.getValue();
88 if (valInit == init)
89 return true;
90 if (auto *di = dyn_cast<DefInit>(valInit)) {
91 if (findUse(*di->getDef(), init, known))
92 return memoize(true);
93 } else if (auto *di = dyn_cast<DagInit>(valInit)) {
94 for (Init *arg : di->getArgs())
95 if (auto *di = dyn_cast<DefInit>(arg))
96 if (findUse(*di->getDef(), init, known))
97 return memoize(true);
98 } else if (ListInit *li = dyn_cast<ListInit>(valInit)) {
99 for (Init *jt : li->getValues())
100 if (jt == init)
101 return memoize(true);
102 }
103 }
104 return memoize(false);
105 }
106
warnOfDeprecatedUses(RecordKeeper & records)107 void warnOfDeprecatedUses(RecordKeeper &records) {
108 // This performs a direct check for any def marked as deprecated and then
109 // finds all uses of deprecated def. Deprecated defs are not expected to be
110 // either numerous or long lived.
111 bool deprecatedDefsFounds = false;
112 for (auto &it : records.getDefs()) {
113 const RecordVal *r = it.second->getValue("odsDeprecated");
114 if (!r || !r->getValue())
115 continue;
116
117 llvm::DenseMap<Record *, bool> hasUse;
118 if (auto *si = dyn_cast<StringInit>(r->getValue())) {
119 for (auto &jt : records.getDefs()) {
120 // Skip anonymous defs.
121 if (jt.second->isAnonymous())
122 continue;
123 // Skip all outside main file to avoid flagging redundantly.
124 unsigned buf =
125 SrcMgr.FindBufferContainingLoc(jt.second->getLoc().front());
126 if (buf != SrcMgr.getMainFileID())
127 continue;
128
129 if (findUse(*jt.second, it.second->getDefInit(), hasUse)) {
130 PrintWarning(jt.second->getLoc(),
131 "Using deprecated def `" + it.first + "`");
132 PrintNote(si->getAsUnquotedString());
133 deprecatedDefsFounds = true;
134 }
135 }
136 }
137 }
138 if (deprecatedDefsFounds && actionOnDeprecated == DeprecatedAction::Error)
139 PrintFatalNote("Error'ing out due to deprecated defs");
140 }
141
142 // TableGenMain requires a function pointer so this function is passed in which
143 // simply wraps the call to the generator.
mlirTableGenMain(raw_ostream & os,RecordKeeper & records)144 static bool mlirTableGenMain(raw_ostream &os, RecordKeeper &records) {
145 if (actionOnDeprecated != DeprecatedAction::None)
146 warnOfDeprecatedUses(records);
147
148 if (!generator) {
149 os << records;
150 return false;
151 }
152 return generator->invoke(records, os);
153 }
154
main(int argc,char ** argv)155 int main(int argc, char **argv) {
156 llvm::InitLLVM y(argc, argv);
157 llvm::cl::opt<const mlir::GenInfo *, false, mlir::GenNameParser> generator(
158 "", llvm::cl::desc("Generator to run"));
159 cl::ParseCommandLineOptions(argc, argv);
160 ::generator = generator.getValue();
161
162 return TableGenMain(argv[0], &mlirTableGenMain);
163 }
164