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/SmallPtrSet.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/TableGen/Error.h"
14 #include "llvm/TableGen/Record.h"
15 
16 using namespace mlir;
17 using namespace mlir::tblgen;
18 
19 //===----------------------------------------------------------------------===//
20 // AttrOrTypeBuilder
21 //===----------------------------------------------------------------------===//
22 
23 /// Returns true if this builder is able to infer the MLIRContext parameter.
24 bool AttrOrTypeBuilder::hasInferredContextParameter() const {
25   return def->getValueAsBit("hasInferredContextParam");
26 }
27 
28 //===----------------------------------------------------------------------===//
29 // AttrOrTypeDef
30 //===----------------------------------------------------------------------===//
31 
32 AttrOrTypeDef::AttrOrTypeDef(const llvm::Record *def) : def(def) {
33   // Populate the builders.
34   auto *builderList =
35       dyn_cast_or_null<llvm::ListInit>(def->getValueInit("builders"));
36   if (builderList && !builderList->empty()) {
37     for (llvm::Init *init : builderList->getValues()) {
38       AttrOrTypeBuilder builder(cast<llvm::DefInit>(init)->getDef(),
39                                 def->getLoc());
40 
41       // Ensure that all parameters have names.
42       for (const AttrOrTypeBuilder::Parameter &param :
43            builder.getParameters()) {
44         if (!param.getName())
45           PrintFatalError(def->getLoc(), "builder parameters must have a name");
46       }
47       builders.emplace_back(builder);
48     }
49   }
50 
51   // Populate the traits.
52   if (auto *traitList = def->getValueAsListInit("traits")) {
53     SmallPtrSet<const llvm::Init *, 32> traitSet;
54     traits.reserve(traitSet.size());
55     for (auto *traitInit : *traitList)
56       if (traitSet.insert(traitInit).second)
57         traits.push_back(Trait::create(traitInit));
58   }
59 
60   // Populate the parameters.
61   if (auto *parametersDag = def->getValueAsDag("parameters")) {
62     for (unsigned i = 0, e = parametersDag->getNumArgs(); i < e; ++i)
63       parameters.push_back(AttrOrTypeParameter(parametersDag, i));
64   }
65 
66   // Verify the use of the mnemonic field.
67   bool hasCppFormat = hasCustomAssemblyFormat();
68   bool hasDeclarativeFormat = getAssemblyFormat().has_value();
69   if (getMnemonic()) {
70     if (hasCppFormat && hasDeclarativeFormat) {
71       PrintFatalError(getLoc(), "cannot specify both 'assemblyFormat' "
72                                 "and 'hasCustomAssemblyFormat'");
73     }
74     if (!parameters.empty() && !hasCppFormat && !hasDeclarativeFormat) {
75       PrintFatalError(getLoc(),
76                       "must specify either 'assemblyFormat' or "
77                       "'hasCustomAssemblyFormat' when 'mnemonic' is set");
78     }
79   } else if (hasCppFormat || hasDeclarativeFormat) {
80     PrintFatalError(getLoc(),
81                     "'assemblyFormat' or 'hasCustomAssemblyFormat' can only be "
82                     "used when 'mnemonic' is set");
83   }
84   // Assembly format parser requires builders with the same prototype
85   // as the default-builders.
86   // TODO: attempt to detect when a custom builder matches the prototype.
87   if (hasDeclarativeFormat && skipDefaultBuilders()) {
88     PrintWarning(getLoc(),
89                  "using 'assemblyFormat' with 'skipDefaultBuilders=1' may "
90                  "result in C++ compilation errors");
91   }
92   // Assembly format printer requires accessors to be generated.
93   if (hasDeclarativeFormat && !genAccessors()) {
94     PrintFatalError(getLoc(),
95                     "'assemblyFormat' requires 'genAccessors' to be true");
96   }
97 }
98 
99 Dialect AttrOrTypeDef::getDialect() const {
100   auto *dialect = dyn_cast<llvm::DefInit>(def->getValue("dialect")->getValue());
101   return Dialect(dialect ? dialect->getDef() : nullptr);
102 }
103 
104 StringRef AttrOrTypeDef::getName() const { return def->getName(); }
105 
106 StringRef AttrOrTypeDef::getCppClassName() const {
107   return def->getValueAsString("cppClassName");
108 }
109 
110 StringRef AttrOrTypeDef::getCppBaseClassName() const {
111   return def->getValueAsString("cppBaseClassName");
112 }
113 
114 bool AttrOrTypeDef::hasDescription() const {
115   const llvm::RecordVal *desc = def->getValue("description");
116   return desc && isa<llvm::StringInit>(desc->getValue());
117 }
118 
119 StringRef AttrOrTypeDef::getDescription() const {
120   return def->getValueAsString("description");
121 }
122 
123 bool AttrOrTypeDef::hasSummary() const {
124   const llvm::RecordVal *summary = def->getValue("summary");
125   return summary && isa<llvm::StringInit>(summary->getValue());
126 }
127 
128 StringRef AttrOrTypeDef::getSummary() const {
129   return def->getValueAsString("summary");
130 }
131 
132 StringRef AttrOrTypeDef::getStorageClassName() const {
133   return def->getValueAsString("storageClass");
134 }
135 
136 StringRef AttrOrTypeDef::getStorageNamespace() const {
137   return def->getValueAsString("storageNamespace");
138 }
139 
140 bool AttrOrTypeDef::genStorageClass() const {
141   return def->getValueAsBit("genStorageClass");
142 }
143 
144 bool AttrOrTypeDef::hasStorageCustomConstructor() const {
145   return def->getValueAsBit("hasStorageCustomConstructor");
146 }
147 
148 unsigned AttrOrTypeDef::getNumParameters() const {
149   auto *parametersDag = def->getValueAsDag("parameters");
150   return parametersDag ? parametersDag->getNumArgs() : 0;
151 }
152 
153 Optional<StringRef> AttrOrTypeDef::getMnemonic() const {
154   return def->getValueAsOptionalString("mnemonic");
155 }
156 
157 bool AttrOrTypeDef::hasCustomAssemblyFormat() const {
158   return def->getValueAsBit("hasCustomAssemblyFormat");
159 }
160 
161 Optional<StringRef> AttrOrTypeDef::getAssemblyFormat() const {
162   return def->getValueAsOptionalString("assemblyFormat");
163 }
164 
165 bool AttrOrTypeDef::genAccessors() const {
166   return def->getValueAsBit("genAccessors");
167 }
168 
169 bool AttrOrTypeDef::genVerifyDecl() const {
170   return def->getValueAsBit("genVerifyDecl");
171 }
172 
173 Optional<StringRef> AttrOrTypeDef::getExtraDecls() const {
174   auto value = def->getValueAsString("extraClassDeclaration");
175   return value.empty() ? Optional<StringRef>() : value;
176 }
177 
178 ArrayRef<SMLoc> AttrOrTypeDef::getLoc() const { return def->getLoc(); }
179 
180 bool AttrOrTypeDef::skipDefaultBuilders() const {
181   return def->getValueAsBit("skipDefaultBuilders");
182 }
183 
184 bool AttrOrTypeDef::operator==(const AttrOrTypeDef &other) const {
185   return def == other.def;
186 }
187 
188 bool AttrOrTypeDef::operator<(const AttrOrTypeDef &other) const {
189   return getName() < other.getName();
190 }
191 
192 //===----------------------------------------------------------------------===//
193 // AttrDef
194 //===----------------------------------------------------------------------===//
195 
196 Optional<StringRef> AttrDef::getTypeBuilder() const {
197   return def->getValueAsOptionalString("typeBuilder");
198 }
199 
200 bool AttrDef::classof(const AttrOrTypeDef *def) {
201   return def->getDef()->isSubClassOf("AttrDef");
202 }
203 
204 //===----------------------------------------------------------------------===//
205 // AttrOrTypeParameter
206 //===----------------------------------------------------------------------===//
207 
208 template <typename InitT>
209 auto AttrOrTypeParameter::getDefValue(StringRef name) const {
210   Optional<decltype(std::declval<InitT>().getValue())> result;
211   if (auto *param = dyn_cast<llvm::DefInit>(getDef()))
212     if (auto *init = param->getDef()->getValue(name))
213       if (auto *value = dyn_cast_or_null<InitT>(init->getValue()))
214         result = value->getValue();
215   return result;
216 }
217 
218 bool AttrOrTypeParameter::isAnonymous() const {
219   return !def->getArgName(index);
220 }
221 
222 StringRef AttrOrTypeParameter::getName() const {
223   return def->getArgName(index)->getValue();
224 }
225 
226 std::string AttrOrTypeParameter::getAccessorName() const {
227   return "get" +
228          llvm::convertToCamelFromSnakeCase(getName(), /*capitalizeFirst=*/true);
229 }
230 
231 Optional<StringRef> AttrOrTypeParameter::getAllocator() const {
232   return getDefValue<llvm::StringInit>("allocator");
233 }
234 
235 StringRef AttrOrTypeParameter::getComparator() const {
236   return getDefValue<llvm::StringInit>("comparator").value_or("$_lhs == $_rhs");
237 }
238 
239 StringRef AttrOrTypeParameter::getCppType() const {
240   if (auto *stringType = dyn_cast<llvm::StringInit>(getDef()))
241     return stringType->getValue();
242   return getDefValue<llvm::StringInit>("cppType").value();
243 }
244 
245 StringRef AttrOrTypeParameter::getCppAccessorType() const {
246   return getDefValue<llvm::StringInit>("cppAccessorType")
247       .value_or(getCppType());
248 }
249 
250 StringRef AttrOrTypeParameter::getCppStorageType() const {
251   return getDefValue<llvm::StringInit>("cppStorageType").value_or(getCppType());
252 }
253 
254 StringRef AttrOrTypeParameter::getConvertFromStorage() const {
255   return getDefValue<llvm::StringInit>("convertFromStorage").value_or("$_self");
256 }
257 
258 Optional<StringRef> AttrOrTypeParameter::getParser() const {
259   return getDefValue<llvm::StringInit>("parser");
260 }
261 
262 Optional<StringRef> AttrOrTypeParameter::getPrinter() const {
263   return getDefValue<llvm::StringInit>("printer");
264 }
265 
266 Optional<StringRef> AttrOrTypeParameter::getSummary() const {
267   return getDefValue<llvm::StringInit>("summary");
268 }
269 
270 StringRef AttrOrTypeParameter::getSyntax() const {
271   if (auto *stringType = dyn_cast<llvm::StringInit>(getDef()))
272     return stringType->getValue();
273   return getDefValue<llvm::StringInit>("syntax").value_or(getCppType());
274 }
275 
276 bool AttrOrTypeParameter::isOptional() const {
277   // Parameters with default values are automatically optional.
278   return getDefValue<llvm::BitInit>("isOptional").value_or(false) ||
279          getDefaultValue();
280 }
281 
282 Optional<StringRef> AttrOrTypeParameter::getDefaultValue() const {
283   return getDefValue<llvm::StringInit>("defaultValue");
284 }
285 
286 llvm::Init *AttrOrTypeParameter::getDef() const { return def->getArg(index); }
287 
288 //===----------------------------------------------------------------------===//
289 // AttributeSelfTypeParameter
290 //===----------------------------------------------------------------------===//
291 
292 bool AttributeSelfTypeParameter::classof(const AttrOrTypeParameter *param) {
293   llvm::Init *paramDef = param->getDef();
294   if (auto *paramDefInit = dyn_cast<llvm::DefInit>(paramDef))
295     return paramDefInit->getDef()->isSubClassOf("AttributeSelfTypeParameter");
296   return false;
297 }
298