1 | //===- TosaUtilsGen.cpp - Tosa utility generator -===// |
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 | // TosaUtilsGen generates common utility functions for Tosa validation. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "mlir/TableGen/Attribute.h" |
14 | #include "mlir/TableGen/CodeGenHelpers.h" |
15 | #include "mlir/TableGen/EnumInfo.h" |
16 | #include "mlir/TableGen/Format.h" |
17 | #include "mlir/TableGen/GenInfo.h" |
18 | #include "mlir/TableGen/Operator.h" |
19 | #include "llvm/ADT/STLExtras.h" |
20 | #include "llvm/ADT/Sequence.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringExtras.h" |
23 | #include "llvm/ADT/StringMap.h" |
24 | #include "llvm/ADT/StringRef.h" |
25 | #include "llvm/ADT/StringSet.h" |
26 | #include "llvm/Support/FormatVariadic.h" |
27 | #include "llvm/Support/raw_ostream.h" |
28 | #include "llvm/TableGen/Error.h" |
29 | #include "llvm/TableGen/Record.h" |
30 | #include "llvm/TableGen/TableGenBackend.h" |
31 | |
32 | #include <list> |
33 | #include <optional> |
34 | |
35 | using llvm::formatv; |
36 | using llvm::raw_ostream; |
37 | using llvm::Record; |
38 | using llvm::RecordKeeper; |
39 | using llvm::StringMap; |
40 | using llvm::StringRef; |
41 | using mlir::tblgen::Operator; |
42 | |
43 | //===----------------------------------------------------------------------===// |
44 | // Availability Wrapper Class |
45 | //===----------------------------------------------------------------------===// |
46 | |
47 | namespace { |
48 | // Wrapper class with helper methods for accessing availability defined in |
49 | // TableGen. |
50 | class Availability { |
51 | public: |
52 | explicit Availability(const Record *def); |
53 | |
54 | // Returns the name of the direct TableGen class for this availability |
55 | // instance. |
56 | StringRef getClass() const; |
57 | |
58 | // Returns the name of the query function insided the generated C++ interface. |
59 | StringRef getQueryFnName() const; |
60 | |
61 | // Returns the return type of the query function insided the generated C++ |
62 | // interface. |
63 | StringRef getQueryFnRetType() const; |
64 | |
65 | // Returns the code for merging availability requirements. |
66 | StringRef getMergeActionCode() const; |
67 | |
68 | // Returns the initializer expression for initializing the final availability |
69 | // requirements. |
70 | StringRef getMergeInitializer() const; |
71 | |
72 | // Returns the C++ statements for preparing availability instance. |
73 | StringRef getMergeInstancePreparation() const; |
74 | |
75 | // Returns the concrete availability instance carried in this case. |
76 | StringRef getMergeInstance() const; |
77 | |
78 | // Returns the underlying LLVM TableGen Record. |
79 | const llvm::Record *getDef() const { return def; } |
80 | |
81 | private: |
82 | // The TableGen definition of this availability. |
83 | const llvm::Record *def; |
84 | }; |
85 | } // namespace |
86 | |
87 | Availability::Availability(const llvm::Record *def) : def(def) { |
88 | assert(def->isSubClassOf("Availability" ) && |
89 | "must be subclass of TableGen 'Availability' class" ); |
90 | } |
91 | |
92 | StringRef Availability::getClass() const { |
93 | if (def->getDirectSuperClasses().size() != 1) { |
94 | PrintFatalError(ErrorLoc: def->getLoc(), |
95 | Msg: "expected to only have one direct superclass" ); |
96 | } |
97 | return def->getDirectSuperClasses().front().first->getName(); |
98 | } |
99 | |
100 | StringRef Availability::getQueryFnRetType() const { |
101 | return def->getValueAsString(FieldName: "queryFnRetType" ); |
102 | } |
103 | |
104 | StringRef Availability::getQueryFnName() const { |
105 | return def->getValueAsString(FieldName: "queryFnName" ); |
106 | } |
107 | |
108 | StringRef Availability::getMergeActionCode() const { |
109 | return def->getValueAsString(FieldName: "mergeAction" ); |
110 | } |
111 | |
112 | StringRef Availability::getMergeInitializer() const { |
113 | return def->getValueAsString(FieldName: "initializer" ); |
114 | } |
115 | |
116 | StringRef Availability::getMergeInstancePreparation() const { |
117 | return def->getValueAsString(FieldName: "instancePreparation" ); |
118 | } |
119 | |
120 | StringRef Availability::getMergeInstance() const { |
121 | return def->getValueAsString(FieldName: "instance" ); |
122 | } |
123 | |
124 | // Returns the availability spec of the given `def`. |
125 | std::vector<Availability> getAvailabilities(const Record &def) { |
126 | std::vector<Availability> availabilities; |
127 | |
128 | if (def.getValue(Name: "availability" )) { |
129 | std::vector<const Record *> availDefs = |
130 | def.getValueAsListOfDefs(FieldName: "availability" ); |
131 | availabilities.reserve(n: availDefs.size()); |
132 | for (const Record *avail : availDefs) |
133 | availabilities.emplace_back(args&: avail); |
134 | } |
135 | |
136 | return availabilities; |
137 | } |
138 | |
139 | //===----------------------------------------------------------------------===// |
140 | // Tosa Availability Impl AutoGen |
141 | //===----------------------------------------------------------------------===// |
142 | |
143 | static void emitAvailabilityImpl(const Operator &srcOp, raw_ostream &os) { |
144 | mlir::tblgen::FmtContext fctx; |
145 | fctx.addSubst(placeholder: "overall" , subst: "tblgen_overall" ); |
146 | |
147 | std::vector<Availability> opAvailabilities = |
148 | getAvailabilities(def: srcOp.getDef()); |
149 | |
150 | // First collect all availability classes this op should implement. |
151 | // All availability instances keep information for the generated interface and |
152 | // the instance's specific requirement. Here we remember a random instance so |
153 | // we can get the information regarding the generated interface. |
154 | llvm::StringMap<Availability> availClasses; |
155 | for (const Availability &avail : opAvailabilities) |
156 | availClasses.try_emplace(Key: avail.getClass(), Args: avail); |
157 | |
158 | // Then generate implementation for each availability class. |
159 | for (const auto &availClass : availClasses) { |
160 | StringRef availClassName = availClass.getKey(); |
161 | Availability avail = availClass.getValue(); |
162 | |
163 | // Generate the implementation method signature. |
164 | os << formatv(Fmt: "{0} {1}::{2}() {{\n" , Vals: avail.getQueryFnRetType(), |
165 | Vals: srcOp.getCppClassName(), Vals: avail.getQueryFnName()); |
166 | |
167 | // Create the variable for the final requirement and initialize it. |
168 | os << formatv(Fmt: " {0} tblgen_overall = {1};\n" , Vals: avail.getQueryFnRetType(), |
169 | Vals: avail.getMergeInitializer()); |
170 | |
171 | // Update with the op's specific availability spec. |
172 | for (const Availability &avail : opAvailabilities) |
173 | if (avail.getClass() == availClassName && |
174 | (!avail.getMergeInstancePreparation().empty() || |
175 | !avail.getMergeActionCode().empty())) { |
176 | os << " {\n " |
177 | // Prepare this instance. |
178 | << avail.getMergeInstancePreparation() |
179 | << "\n " |
180 | // Merge this instance. |
181 | << std::string( |
182 | tgfmt(fmt: avail.getMergeActionCode(), |
183 | ctx: &fctx.addSubst(placeholder: "instance" , subst: avail.getMergeInstance()))) |
184 | << ";\n }\n" ; |
185 | } |
186 | |
187 | os << " return tblgen_overall;\n" ; |
188 | os << "}\n" ; |
189 | } |
190 | } |
191 | |
192 | static bool emitAvailabilityImpl(const RecordKeeper &recordKeeper, |
193 | raw_ostream &os) { |
194 | llvm::emitSourceFileHeader(Desc: "Tosa Op Availability Implementations" , OS&: os, |
195 | Record: recordKeeper); |
196 | |
197 | auto defs = recordKeeper.getAllDerivedDefinitions(ClassName: "Tosa_Op" ); |
198 | for (const auto *def : defs) { |
199 | Operator op(def); |
200 | if (def->getValueAsBit(FieldName: "autogenAvailability" )) |
201 | emitAvailabilityImpl(srcOp: op, os); |
202 | } |
203 | return false; |
204 | } |
205 | |
206 | //===----------------------------------------------------------------------===// |
207 | // Op Availability Implementation Hook Registration |
208 | //===----------------------------------------------------------------------===// |
209 | |
210 | static mlir::GenRegistration |
211 | genOpAvailabilityImpl("gen-tosa-avail-impls" , |
212 | "Generate Tosa operation utility definitions" , |
213 | [](const RecordKeeper &records, raw_ostream &os) { |
214 | return emitAvailabilityImpl(recordKeeper: records, os); |
215 | }); |
216 | |