xref: /llvm-project/mlir/lib/TableGen/AttrOrTypeDef.cpp (revision 659192b1843c4af180700783caca4cdc7afa3eab)
1 //===- AttrOrTypeDef.cpp - AttrOrTypeDef wrapper classes ------------------===//
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 #include "mlir/TableGen/AttrOrTypeDef.h"
10 #include "mlir/TableGen/Dialect.h"
11 #include "llvm/ADT/FunctionExtras.h"
12 #include "llvm/ADT/SmallPtrSet.h"
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/Support/ErrorHandling.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/Record.h"
17 
18 using namespace mlir;
19 using namespace mlir::tblgen;
20 using llvm::DefInit;
21 using llvm::Init;
22 using llvm::ListInit;
23 using llvm::Record;
24 using llvm::RecordVal;
25 using llvm::StringInit;
26 
27 //===----------------------------------------------------------------------===//
28 // AttrOrTypeBuilder
29 //===----------------------------------------------------------------------===//
30 
31 std::optional<StringRef> AttrOrTypeBuilder::getReturnType() const {
32   std::optional<StringRef> type = def->getValueAsOptionalString("returnType");
33   return type && !type->empty() ? type : std::nullopt;
34 }
35 
36 bool AttrOrTypeBuilder::hasInferredContextParameter() const {
37   return def->getValueAsBit("hasInferredContextParam");
38 }
39 
40 //===----------------------------------------------------------------------===//
41 // AttrOrTypeDef
42 //===----------------------------------------------------------------------===//
43 
44 AttrOrTypeDef::AttrOrTypeDef(const Record *def) : def(def) {
45   // Populate the builders.
46   const auto *builderList =
47       dyn_cast_or_null<ListInit>(def->getValueInit("builders"));
48   if (builderList && !builderList->empty()) {
49     for (const Init *init : builderList->getValues()) {
50       AttrOrTypeBuilder builder(cast<DefInit>(init)->getDef(), def->getLoc());
51 
52       // Ensure that all parameters have names.
53       for (const AttrOrTypeBuilder::Parameter &param :
54            builder.getParameters()) {
55         if (!param.getName())
56           PrintFatalError(def->getLoc(), "builder parameters must have a name");
57       }
58       builders.emplace_back(builder);
59     }
60   }
61 
62   // Populate the traits.
63   if (auto *traitList = def->getValueAsListInit("traits")) {
64     SmallPtrSet<const Init *, 32> traitSet;
65     traits.reserve(traitSet.size());
66     llvm::unique_function<void(const ListInit *)> processTraitList =
67         [&](const ListInit *traitList) {
68           for (auto *traitInit : *traitList) {
69             if (!traitSet.insert(traitInit).second)
70               continue;
71 
72             // If this is an interface, add any bases to the trait list.
73             auto *traitDef = cast<DefInit>(traitInit)->getDef();
74             if (traitDef->isSubClassOf("Interface")) {
75               if (auto *bases = traitDef->getValueAsListInit("baseInterfaces"))
76                 processTraitList(bases);
77             }
78 
79             traits.push_back(Trait::create(traitInit));
80           }
81         };
82     processTraitList(traitList);
83   }
84 
85   // Populate the parameters.
86   if (auto *parametersDag = def->getValueAsDag("parameters")) {
87     for (unsigned i = 0, e = parametersDag->getNumArgs(); i < e; ++i)
88       parameters.push_back(AttrOrTypeParameter(parametersDag, i));
89   }
90 
91   // Verify the use of the mnemonic field.
92   bool hasCppFormat = hasCustomAssemblyFormat();
93   bool hasDeclarativeFormat = getAssemblyFormat().has_value();
94   if (getMnemonic()) {
95     if (hasCppFormat && hasDeclarativeFormat) {
96       PrintFatalError(getLoc(), "cannot specify both 'assemblyFormat' "
97                                 "and 'hasCustomAssemblyFormat'");
98     }
99     if (!parameters.empty() && !hasCppFormat && !hasDeclarativeFormat) {
100       PrintFatalError(getLoc(),
101                       "must specify either 'assemblyFormat' or "
102                       "'hasCustomAssemblyFormat' when 'mnemonic' is set");
103     }
104   } else if (hasCppFormat || hasDeclarativeFormat) {
105     PrintFatalError(getLoc(),
106                     "'assemblyFormat' or 'hasCustomAssemblyFormat' can only be "
107                     "used when 'mnemonic' is set");
108   }
109   // Assembly format printer requires accessors to be generated.
110   if (hasDeclarativeFormat && !genAccessors()) {
111     PrintFatalError(getLoc(),
112                     "'assemblyFormat' requires 'genAccessors' to be true");
113   }
114   // TODO: Ensure that a suitable builder prototype can be generated:
115   // https://llvm.org/PR56415
116 }
117 
118 Dialect AttrOrTypeDef::getDialect() const {
119   const auto *dialect = dyn_cast<DefInit>(def->getValue("dialect")->getValue());
120   return Dialect(dialect ? dialect->getDef() : nullptr);
121 }
122 
123 StringRef AttrOrTypeDef::getName() const { return def->getName(); }
124 
125 StringRef AttrOrTypeDef::getCppClassName() const {
126   return def->getValueAsString("cppClassName");
127 }
128 
129 StringRef AttrOrTypeDef::getCppBaseClassName() const {
130   return def->getValueAsString("cppBaseClassName");
131 }
132 
133 bool AttrOrTypeDef::hasDescription() const {
134   const RecordVal *desc = def->getValue("description");
135   return desc && isa<StringInit>(desc->getValue());
136 }
137 
138 StringRef AttrOrTypeDef::getDescription() const {
139   return def->getValueAsString("description");
140 }
141 
142 bool AttrOrTypeDef::hasSummary() const {
143   const RecordVal *summary = def->getValue("summary");
144   return summary && isa<StringInit>(summary->getValue());
145 }
146 
147 StringRef AttrOrTypeDef::getSummary() const {
148   return def->getValueAsString("summary");
149 }
150 
151 StringRef AttrOrTypeDef::getStorageClassName() const {
152   return def->getValueAsString("storageClass");
153 }
154 
155 StringRef AttrOrTypeDef::getStorageNamespace() const {
156   return def->getValueAsString("storageNamespace");
157 }
158 
159 bool AttrOrTypeDef::genStorageClass() const {
160   return def->getValueAsBit("genStorageClass");
161 }
162 
163 bool AttrOrTypeDef::hasStorageCustomConstructor() const {
164   return def->getValueAsBit("hasStorageCustomConstructor");
165 }
166 
167 unsigned AttrOrTypeDef::getNumParameters() const {
168   auto *parametersDag = def->getValueAsDag("parameters");
169   return parametersDag ? parametersDag->getNumArgs() : 0;
170 }
171 
172 std::optional<StringRef> AttrOrTypeDef::getMnemonic() const {
173   return def->getValueAsOptionalString("mnemonic");
174 }
175 
176 bool AttrOrTypeDef::hasCustomAssemblyFormat() const {
177   return def->getValueAsBit("hasCustomAssemblyFormat");
178 }
179 
180 std::optional<StringRef> AttrOrTypeDef::getAssemblyFormat() const {
181   return def->getValueAsOptionalString("assemblyFormat");
182 }
183 
184 bool AttrOrTypeDef::genAccessors() const {
185   return def->getValueAsBit("genAccessors");
186 }
187 
188 bool AttrOrTypeDef::genVerifyDecl() const {
189   return def->getValueAsBit("genVerifyDecl");
190 }
191 
192 bool AttrOrTypeDef::genVerifyInvariantsImpl() const {
193   return any_of(parameters, [](const AttrOrTypeParameter &p) {
194     return p.getConstraint() != std::nullopt;
195   });
196 }
197 
198 std::optional<StringRef> AttrOrTypeDef::getExtraDecls() const {
199   auto value = def->getValueAsString("extraClassDeclaration");
200   return value.empty() ? std::optional<StringRef>() : value;
201 }
202 
203 std::optional<StringRef> AttrOrTypeDef::getExtraDefs() const {
204   auto value = def->getValueAsString("extraClassDefinition");
205   return value.empty() ? std::optional<StringRef>() : value;
206 }
207 
208 ArrayRef<SMLoc> AttrOrTypeDef::getLoc() const { return def->getLoc(); }
209 
210 bool AttrOrTypeDef::skipDefaultBuilders() const {
211   return def->getValueAsBit("skipDefaultBuilders");
212 }
213 
214 bool AttrOrTypeDef::operator==(const AttrOrTypeDef &other) const {
215   return def == other.def;
216 }
217 
218 bool AttrOrTypeDef::operator<(const AttrOrTypeDef &other) const {
219   return getName() < other.getName();
220 }
221 
222 //===----------------------------------------------------------------------===//
223 // AttrDef
224 //===----------------------------------------------------------------------===//
225 
226 std::optional<StringRef> AttrDef::getTypeBuilder() const {
227   return def->getValueAsOptionalString("typeBuilder");
228 }
229 
230 bool AttrDef::classof(const AttrOrTypeDef *def) {
231   return def->getDef()->isSubClassOf("AttrDef");
232 }
233 
234 StringRef AttrDef::getAttrName() const {
235   return def->getValueAsString("attrName");
236 }
237 
238 //===----------------------------------------------------------------------===//
239 // TypeDef
240 //===----------------------------------------------------------------------===//
241 
242 bool TypeDef::classof(const AttrOrTypeDef *def) {
243   return def->getDef()->isSubClassOf("TypeDef");
244 }
245 
246 StringRef TypeDef::getTypeName() const {
247   return def->getValueAsString("typeName");
248 }
249 
250 //===----------------------------------------------------------------------===//
251 // AttrOrTypeParameter
252 //===----------------------------------------------------------------------===//
253 
254 template <typename InitT>
255 auto AttrOrTypeParameter::getDefValue(StringRef name) const {
256   std::optional<decltype(std::declval<InitT>().getValue())> result;
257   if (const auto *param = dyn_cast<DefInit>(getDef()))
258     if (const auto *init = param->getDef()->getValue(name))
259       if (const auto *value = dyn_cast_or_null<InitT>(init->getValue()))
260         result = value->getValue();
261   return result;
262 }
263 
264 bool AttrOrTypeParameter::isAnonymous() const {
265   return !def->getArgName(index);
266 }
267 
268 StringRef AttrOrTypeParameter::getName() const {
269   return def->getArgName(index)->getValue();
270 }
271 
272 std::string AttrOrTypeParameter::getAccessorName() const {
273   return "get" +
274          llvm::convertToCamelFromSnakeCase(getName(), /*capitalizeFirst=*/true);
275 }
276 
277 std::optional<StringRef> AttrOrTypeParameter::getAllocator() const {
278   return getDefValue<StringInit>("allocator");
279 }
280 
281 StringRef AttrOrTypeParameter::getComparator() const {
282   return getDefValue<StringInit>("comparator").value_or("$_lhs == $_rhs");
283 }
284 
285 StringRef AttrOrTypeParameter::getCppType() const {
286   if (auto *stringType = dyn_cast<StringInit>(getDef()))
287     return stringType->getValue();
288   auto cppType = getDefValue<StringInit>("cppType");
289   if (cppType)
290     return *cppType;
291   if (const auto *init = dyn_cast<DefInit>(getDef()))
292     llvm::PrintFatalError(
293         init->getDef()->getLoc(),
294         Twine("Missing `cppType` field in Attribute/Type parameter: ") +
295             init->getAsString());
296   llvm::report_fatal_error(
297       Twine("Missing `cppType` field in Attribute/Type parameter: ") +
298           getDef()->getAsString(),
299       /*gen_crash_diag=*/false);
300 }
301 
302 StringRef AttrOrTypeParameter::getCppAccessorType() const {
303   return getDefValue<StringInit>("cppAccessorType").value_or(getCppType());
304 }
305 
306 StringRef AttrOrTypeParameter::getCppStorageType() const {
307   return getDefValue<StringInit>("cppStorageType").value_or(getCppType());
308 }
309 
310 StringRef AttrOrTypeParameter::getConvertFromStorage() const {
311   return getDefValue<StringInit>("convertFromStorage").value_or("$_self");
312 }
313 
314 std::optional<StringRef> AttrOrTypeParameter::getParser() const {
315   return getDefValue<StringInit>("parser");
316 }
317 
318 std::optional<StringRef> AttrOrTypeParameter::getPrinter() const {
319   return getDefValue<StringInit>("printer");
320 }
321 
322 std::optional<StringRef> AttrOrTypeParameter::getSummary() const {
323   return getDefValue<StringInit>("summary");
324 }
325 
326 StringRef AttrOrTypeParameter::getSyntax() const {
327   if (auto *stringType = dyn_cast<StringInit>(getDef()))
328     return stringType->getValue();
329   return getDefValue<StringInit>("syntax").value_or(getCppType());
330 }
331 
332 bool AttrOrTypeParameter::isOptional() const {
333   return getDefaultValue().has_value();
334 }
335 
336 std::optional<StringRef> AttrOrTypeParameter::getDefaultValue() const {
337   std::optional<StringRef> result = getDefValue<StringInit>("defaultValue");
338   return result && !result->empty() ? result : std::nullopt;
339 }
340 
341 const Init *AttrOrTypeParameter::getDef() const { return def->getArg(index); }
342 
343 std::optional<Constraint> AttrOrTypeParameter::getConstraint() const {
344   if (const auto *param = dyn_cast<DefInit>(getDef()))
345     if (param->getDef()->isSubClassOf("Constraint"))
346       return Constraint(param->getDef());
347   return std::nullopt;
348 }
349 
350 //===----------------------------------------------------------------------===//
351 // AttributeSelfTypeParameter
352 //===----------------------------------------------------------------------===//
353 
354 bool AttributeSelfTypeParameter::classof(const AttrOrTypeParameter *param) {
355   const Init *paramDef = param->getDef();
356   if (const auto *paramDefInit = dyn_cast<DefInit>(paramDef))
357     return paramDefInit->getDef()->isSubClassOf("AttributeSelfTypeParameter");
358   return false;
359 }
360