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