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
35using llvm::formatv;
36using llvm::raw_ostream;
37using llvm::Record;
38using llvm::RecordKeeper;
39using llvm::StringMap;
40using llvm::StringRef;
41using mlir::tblgen::Operator;
42
43//===----------------------------------------------------------------------===//
44// Availability Wrapper Class
45//===----------------------------------------------------------------------===//
46
47namespace {
48// Wrapper class with helper methods for accessing availability defined in
49// TableGen.
50class Availability {
51public:
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
81private:
82 // The TableGen definition of this availability.
83 const llvm::Record *def;
84};
85} // namespace
86
87Availability::Availability(const llvm::Record *def) : def(def) {
88 assert(def->isSubClassOf("Availability") &&
89 "must be subclass of TableGen 'Availability' class");
90}
91
92StringRef 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
100StringRef Availability::getQueryFnRetType() const {
101 return def->getValueAsString(FieldName: "queryFnRetType");
102}
103
104StringRef Availability::getQueryFnName() const {
105 return def->getValueAsString(FieldName: "queryFnName");
106}
107
108StringRef Availability::getMergeActionCode() const {
109 return def->getValueAsString(FieldName: "mergeAction");
110}
111
112StringRef Availability::getMergeInitializer() const {
113 return def->getValueAsString(FieldName: "initializer");
114}
115
116StringRef Availability::getMergeInstancePreparation() const {
117 return def->getValueAsString(FieldName: "instancePreparation");
118}
119
120StringRef Availability::getMergeInstance() const {
121 return def->getValueAsString(FieldName: "instance");
122}
123
124// Returns the availability spec of the given `def`.
125std::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
143static 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
192static 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
210static 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

source code of mlir/tools/mlir-tblgen/TosaUtilsGen.cpp