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 | |
25 | using namespace mlir; |
26 | using namespace llvm; |
27 | |
28 | enum DeprecatedAction { None, Warn, Error }; |
29 | |
30 | static DeprecatedAction actionOnDeprecatedValue; |
31 | |
32 | // Returns if there is a use of `deprecatedInit` in `field`. |
33 | static 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`. |
86 | static 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 | |
93 | static 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. |
125 | static 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. |
129 | static 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 | |
140 | int 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 | |