[rtsan] Remove mkfifoat interceptor (#116997)
[llvm-project.git] / mlir / lib / Dialect / DLTI / DLTI.cpp
blob508e50d42e4cf2f469608dcaf6c585ad55877ab9
1 //===- DLTI.cpp - Data Layout And Target Info MLIR Dialect Implementation -===//
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 //===----------------------------------------------------------------------===//
9 #include "mlir/Dialect/DLTI/DLTI.h"
10 #include "mlir/IR/Builders.h"
11 #include "mlir/IR/BuiltinAttributes.h"
12 #include "mlir/IR/BuiltinDialect.h"
13 #include "mlir/IR/BuiltinOps.h"
14 #include "mlir/IR/BuiltinTypes.h"
15 #include "mlir/IR/Dialect.h"
16 #include "mlir/IR/DialectImplementation.h"
17 #include "llvm/ADT/TypeSwitch.h"
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/MathExtras.h"
23 using namespace mlir;
25 #include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
27 #define GET_ATTRDEF_CLASSES
28 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
30 #define DEBUG_TYPE "dlti"
32 //===----------------------------------------------------------------------===//
33 // Common parsing utility functions.
34 //===----------------------------------------------------------------------===//
36 /// Parse an entry which can either be of the form `key = value` or a
37 /// #dlti.dl_entry attribute. When `tryType=true` the key can be a type,
38 /// otherwise only quoted strings are allowed. The grammar is as follows:
39 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
40 static ParseResult parseKeyValuePair(AsmParser &parser,
41 DataLayoutEntryInterface &entry,
42 bool tryType = false) {
43 Attribute value;
45 if (tryType) {
46 Type type;
47 OptionalParseResult parsedType = parser.parseOptionalType(type);
48 if (parsedType.has_value()) {
49 if (failed(parsedType.value()))
50 return parser.emitError(parser.getCurrentLocation())
51 << "error while parsing type DLTI key";
53 if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
54 return failure();
56 entry = DataLayoutEntryAttr::get(type, value);
57 return ParseResult::success();
61 std::string ident;
62 OptionalParseResult parsedStr = parser.parseOptionalString(&ident);
63 if (parsedStr.has_value() && succeeded(parsedStr.value())) {
64 if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
65 return failure(); // Assume that an error has already been emitted.
67 entry = DataLayoutEntryAttr::get(
68 StringAttr::get(parser.getContext(), ident), value);
69 return ParseResult::success();
72 OptionalParseResult parsedEntry = parser.parseAttribute(entry);
73 if (parsedEntry.has_value()) {
74 if (succeeded(parsedEntry.value()))
75 return parsedEntry.value();
76 return failure(); // Assume that an error has already been emitted.
78 return parser.emitError(parser.getCurrentLocation())
79 << "failed to parse DLTI entry";
82 /// Construct a requested attribute by parsing list of entries occurring within
83 /// a pair of `<` and `>`, optionally allow types as keys and an empty list.
84 /// The grammar is as follows:
85 /// bracketed-entry-list ::=`<` entry-list `>`
86 /// entry-list ::= | entry | entry `,` entry-list
87 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
88 template <class Attr>
89 static Attribute parseAngleBracketedEntries(AsmParser &parser, Type ty,
90 bool tryType = false,
91 bool allowEmpty = false) {
92 SmallVector<DataLayoutEntryInterface> entries;
93 if (failed(parser.parseCommaSeparatedList(
94 AsmParser::Delimiter::LessGreater, [&]() {
95 return parseKeyValuePair(parser, entries.emplace_back(), tryType);
96 })))
97 return {};
99 if (entries.empty() && !allowEmpty) {
100 parser.emitError(parser.getNameLoc()) << "no DLTI entries provided";
101 return {};
104 return Attr::getChecked([&] { return parser.emitError(parser.getNameLoc()); },
105 parser.getContext(), ArrayRef(entries));
108 //===----------------------------------------------------------------------===//
109 // Common printing utility functions.
110 //===----------------------------------------------------------------------===//
112 /// Convert pointer-union keys to strings.
113 static std::string keyToStr(DataLayoutEntryKey key) {
114 std::string buf;
115 TypeSwitch<DataLayoutEntryKey>(key)
116 .Case<StringAttr, Type>( // The only two kinds of key we know of.
117 [&](auto key) { llvm::raw_string_ostream(buf) << key; });
118 return buf;
121 /// Pretty-print entries, each in `key = value` format, separated by commas.
122 template <class T>
123 static void printAngleBracketedEntries(AsmPrinter &os, T &&entries) {
124 os << "<";
125 llvm::interleaveComma(std::forward<T>(entries), os, [&](auto entry) {
126 os << keyToStr(entry.getKey()) << " = " << entry.getValue();
128 os << ">";
131 //===----------------------------------------------------------------------===//
132 // Common verifying utility functions.
133 //===----------------------------------------------------------------------===//
135 /// Verify entries, with the option to disallow types as keys.
136 static LogicalResult verifyEntries(function_ref<InFlightDiagnostic()> emitError,
137 ArrayRef<DataLayoutEntryInterface> entries,
138 bool allowTypes = true) {
139 DenseSet<DataLayoutEntryKey> keys;
140 for (DataLayoutEntryInterface entry : entries) {
141 if (!entry)
142 return emitError() << "contained invalid DLTI entry";
143 DataLayoutEntryKey key = entry.getKey();
144 if (key.isNull())
145 return emitError() << "contained invalid DLTI key";
146 if (!allowTypes && dyn_cast<Type>(key))
147 return emitError() << "type as DLTI key is not allowed";
148 if (auto strKey = dyn_cast<StringAttr>(key))
149 if (strKey.getValue().empty())
150 return emitError() << "empty string as DLTI key is not allowed";
151 if (!keys.insert(key).second)
152 return emitError() << "repeated DLTI key: " << keyToStr(key);
153 if (!entry.getValue())
154 return emitError() << "value associated to DLTI key " << keyToStr(key)
155 << " is invalid";
157 return success();
160 //===----------------------------------------------------------------------===//
161 // DataLayoutEntryAttr
162 //===----------------------------------------------------------------------===//
163 namespace mlir {
164 namespace detail {
165 class DataLayoutEntryAttrStorage : public AttributeStorage {
166 public:
167 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
169 DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
170 : entryKey(entryKey), value(value) {}
172 static DataLayoutEntryAttrStorage *
173 construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
174 return new (allocator.allocate<DataLayoutEntryAttrStorage>())
175 DataLayoutEntryAttrStorage(key.first, key.second);
178 bool operator==(const KeyTy &other) const {
179 return other.first == entryKey && other.second == value;
182 DataLayoutEntryKey entryKey;
183 Attribute value;
185 } // namespace detail
186 } // namespace mlir
188 DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
189 return Base::get(key.getContext(), key, value);
192 DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) {
193 return Base::get(key.getContext(), key, value);
196 DataLayoutEntryKey DataLayoutEntryAttr::getKey() const {
197 return getImpl()->entryKey;
200 Attribute DataLayoutEntryAttr::getValue() const { return getImpl()->value; }
202 /// Parses an attribute with syntax:
203 /// dl-entry-attr ::= `#dlti.` `dl_entry` `<` (type | quoted-string) `,`
204 /// attr `>`
205 Attribute DataLayoutEntryAttr::parse(AsmParser &parser, Type type) {
206 if (failed(parser.parseLess()))
207 return {};
209 Type typeKey = nullptr;
210 std::string identifier;
211 SMLoc idLoc = parser.getCurrentLocation();
212 OptionalParseResult parsedType = parser.parseOptionalType(typeKey);
213 if (parsedType.has_value() && failed(parsedType.value()))
214 return {};
215 if (!parsedType.has_value()) {
216 OptionalParseResult parsedString = parser.parseOptionalString(&identifier);
217 if (!parsedString.has_value() || failed(parsedString.value())) {
218 parser.emitError(idLoc) << "expected a type or a quoted string";
219 return {};
223 Attribute value;
224 if (failed(parser.parseComma()) || failed(parser.parseAttribute(value)) ||
225 failed(parser.parseGreater()))
226 return {};
228 return typeKey ? get(typeKey, value)
229 : get(parser.getBuilder().getStringAttr(identifier), value);
232 void DataLayoutEntryAttr::print(AsmPrinter &printer) const {
233 printer << "<" << keyToStr(getKey()) << ", " << getValue() << ">";
236 //===----------------------------------------------------------------------===//
237 // DLTIMapAttr
238 //===----------------------------------------------------------------------===//
240 /// Parses an attribute with syntax:
241 /// map-attr ::= `#dlti.` `map` `<` entry-list `>`
242 /// entry-list ::= entry | entry `,` entry-list
243 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
244 Attribute MapAttr::parse(AsmParser &parser, Type type) {
245 return parseAngleBracketedEntries<MapAttr>(parser, type, /*tryType=*/true,
246 /*allowEmpty=*/true);
249 void MapAttr::print(AsmPrinter &printer) const {
250 printAngleBracketedEntries(printer, getEntries());
253 LogicalResult MapAttr::verify(function_ref<InFlightDiagnostic()> emitError,
254 ArrayRef<DataLayoutEntryInterface> entries) {
255 return verifyEntries(emitError, entries);
258 //===----------------------------------------------------------------------===//
259 // DataLayoutSpecAttr
260 //===----------------------------------------------------------------------===//
262 LogicalResult
263 DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
264 ArrayRef<DataLayoutEntryInterface> entries) {
265 return verifyEntries(emitError, entries);
268 /// Given a list of old and a list of new entries, overwrites old entries with
269 /// new ones if they have matching keys, appends new entries to the old entry
270 /// list otherwise.
271 static void
272 overwriteDuplicateEntries(SmallVectorImpl<DataLayoutEntryInterface> &oldEntries,
273 ArrayRef<DataLayoutEntryInterface> newEntries) {
274 unsigned oldEntriesSize = oldEntries.size();
275 for (DataLayoutEntryInterface entry : newEntries) {
276 // We expect a small (dozens) number of entries, so it is practically
277 // cheaper to iterate over the list linearly rather than to create an
278 // auxiliary hashmap to avoid duplication. Also note that we never need to
279 // check for duplicate keys the values that were added from `newEntries`.
280 bool replaced = false;
281 for (unsigned i = 0; i < oldEntriesSize; ++i) {
282 if (oldEntries[i].getKey() == entry.getKey()) {
283 oldEntries[i] = entry;
284 replaced = true;
285 break;
288 if (!replaced)
289 oldEntries.push_back(entry);
293 /// Combines a data layout spec into the given lists of entries organized by
294 /// type class and identifier, overwriting them if necessary. Fails to combine
295 /// if the two entries with identical keys are not compatible.
296 static LogicalResult
297 combineOneSpec(DataLayoutSpecInterface spec,
298 DenseMap<TypeID, DataLayoutEntryList> &entriesForType,
299 DenseMap<StringAttr, DataLayoutEntryInterface> &entriesForID) {
300 // A missing spec should be fine.
301 if (!spec)
302 return success();
304 DenseMap<TypeID, DataLayoutEntryList> newEntriesForType;
305 DenseMap<StringAttr, DataLayoutEntryInterface> newEntriesForID;
306 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
308 // Try overwriting the old entries with the new ones.
309 for (auto &kvp : newEntriesForType) {
310 if (!entriesForType.count(kvp.first)) {
311 entriesForType[kvp.first] = std::move(kvp.second);
312 continue;
315 Type typeSample = kvp.second.front().getKey().get<Type>();
316 assert(&typeSample.getDialect() !=
317 typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
318 "unexpected data layout entry for built-in type");
320 auto interface = cast<DataLayoutTypeInterface>(typeSample);
321 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second))
322 return failure();
324 overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
327 for (const auto &kvp : newEntriesForID) {
328 StringAttr id = kvp.second.getKey().get<StringAttr>();
329 Dialect *dialect = id.getReferencedDialect();
330 if (!entriesForID.count(id)) {
331 entriesForID[id] = kvp.second;
332 continue;
335 // Attempt to combine the enties using the dialect interface. If the
336 // dialect is not loaded for some reason, use the default combinator
337 // that conservatively accepts identical entries only.
338 entriesForID[id] =
339 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
340 entriesForID[id], kvp.second)
341 : DataLayoutDialectInterface::defaultCombine(entriesForID[id],
342 kvp.second);
343 if (!entriesForID[id])
344 return failure();
347 return success();
350 DataLayoutSpecAttr
351 DataLayoutSpecAttr::combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
352 // Only combine with attributes of the same kind.
353 // TODO: reconsider this when the need arises.
354 if (any_of(specs, [](DataLayoutSpecInterface spec) {
355 return !llvm::isa<DataLayoutSpecAttr>(spec);
357 return {};
359 // Combine all specs in order, with `this` being the last one.
360 DenseMap<TypeID, DataLayoutEntryList> entriesForType;
361 DenseMap<StringAttr, DataLayoutEntryInterface> entriesForID;
362 for (DataLayoutSpecInterface spec : specs)
363 if (failed(combineOneSpec(spec, entriesForType, entriesForID)))
364 return nullptr;
365 if (failed(combineOneSpec(*this, entriesForType, entriesForID)))
366 return nullptr;
368 // Rebuild the linear list of entries.
369 SmallVector<DataLayoutEntryInterface> entries;
370 llvm::append_range(entries, llvm::make_second_range(entriesForID));
371 for (const auto &kvp : entriesForType)
372 llvm::append_range(entries, kvp.getSecond());
374 return DataLayoutSpecAttr::get(getContext(), entries);
377 StringAttr
378 DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
379 return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
382 StringAttr
383 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
384 return Builder(context).getStringAttr(
385 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
388 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
389 MLIRContext *context) const {
390 return Builder(context).getStringAttr(
391 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
394 StringAttr
395 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
396 return Builder(context).getStringAttr(
397 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
400 StringAttr
401 DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
402 return Builder(context).getStringAttr(
403 DLTIDialect::kDataLayoutStackAlignmentKey);
406 /// Parses an attribute with syntax:
407 /// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
408 /// entry-list ::= | entry | entry `,` entry-list
409 /// entry ::= ((type | quoted-string) = attr) | dl-entry-attr
410 Attribute DataLayoutSpecAttr::parse(AsmParser &parser, Type type) {
411 return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type,
412 /*tryType=*/true,
413 /*allowEmpty=*/true);
416 void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
417 printAngleBracketedEntries(printer, getEntries());
420 //===----------------------------------------------------------------------===//
421 // TargetDeviceSpecAttr
422 //===----------------------------------------------------------------------===//
424 LogicalResult
425 TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
426 ArrayRef<DataLayoutEntryInterface> entries) {
427 return verifyEntries(emitError, entries, /*allowTypes=*/false);
430 /// Parses an attribute with syntax:
431 /// dev-spec-attr ::= `#dlti.` `target_device_spec` `<` entry-list `>`
432 /// entry-list ::= entry | entry `,` entry-list
433 /// entry ::= (quoted-string `=` attr) | dl-entry-attr
434 Attribute TargetDeviceSpecAttr::parse(AsmParser &parser, Type type) {
435 return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type);
438 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
439 printAngleBracketedEntries(printer, getEntries());
442 //===----------------------------------------------------------------------===//
443 // TargetSystemSpecAttr
444 //===----------------------------------------------------------------------===//
446 LogicalResult
447 TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
448 ArrayRef<DataLayoutEntryInterface> entries) {
449 DenseSet<TargetSystemSpecInterface::DeviceID> deviceIds;
451 for (const auto &entry : entries) {
452 auto deviceId =
453 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
454 if (!deviceId)
455 return emitError() << "non-string key of DLTI system spec";
457 if (auto targetDeviceSpec =
458 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
459 if (failed(TargetDeviceSpecAttr::verify(emitError,
460 targetDeviceSpec.getEntries())))
461 return failure(); // Assume sub-verifier outputted error message.
462 } else {
463 return emitError() << "value associated with key " << deviceId
464 << " is not a DLTI device spec";
467 // Check that device IDs are unique across all entries.
468 if (!deviceIds.insert(deviceId).second)
469 return emitError() << "repeated device ID in dlti.target_system_spec: "
470 << deviceId;
473 return success();
476 /// Parses an attribute with syntax:
477 /// sys-spec-attr ::= `#dlti.` `target_system_spec` `<` entry-list `>`
478 /// entry-list ::= entry | entry `,` entry-list
479 /// entry ::= (quoted-string `=` dev-spec-attr) | dl-entry-attr
480 Attribute TargetSystemSpecAttr::parse(AsmParser &parser, Type type) {
481 return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
484 void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
485 printAngleBracketedEntries(printer, getEntries());
488 //===----------------------------------------------------------------------===//
489 // DLTIDialect
490 //===----------------------------------------------------------------------===//
492 /// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
493 /// attached to `op` or such an attr on as close as possible an ancestor. The
494 /// op the attribute is attached to is returned as well.
495 static std::pair<DLTIQueryInterface, Operation *>
496 getClosestQueryable(Operation *op) {
497 DLTIQueryInterface queryable = {};
499 // Search op and its ancestors for the first attached DLTIQueryInterface attr.
500 do {
501 for (NamedAttribute attr : op->getAttrs())
502 if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
503 break;
504 } while (!queryable && (op = op->getParentOp()));
506 return std::pair(queryable, op);
509 FailureOr<Attribute>
510 dlti::query(Operation *op, ArrayRef<DataLayoutEntryKey> keys, bool emitError) {
511 if (keys.empty()) {
512 if (emitError) {
513 auto diag = op->emitError() << "target op of failed DLTI query";
514 diag.attachNote(op->getLoc()) << "no keys provided to attempt query with";
516 return failure();
519 auto [queryable, queryOp] = getClosestQueryable(op);
520 Operation *reportOp = (queryOp ? queryOp : op);
522 if (!queryable) {
523 if (emitError) {
524 auto diag = op->emitError() << "target op of failed DLTI query";
525 diag.attachNote(reportOp->getLoc())
526 << "no DLTI-queryable attrs on target op or any of its ancestors";
528 return failure();
531 Attribute currentAttr = queryable;
532 for (auto &&[idx, key] : llvm::enumerate(keys)) {
533 if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
534 auto maybeAttr = map.query(key);
535 if (failed(maybeAttr)) {
536 if (emitError) {
537 auto diag = op->emitError() << "target op of failed DLTI query";
538 diag.attachNote(reportOp->getLoc())
539 << "key " << keyToStr(key)
540 << " has no DLTI-mapping per attr: " << map;
542 return failure();
544 currentAttr = *maybeAttr;
545 } else {
546 if (emitError) {
547 std::string commaSeparatedKeys;
548 llvm::interleave(
549 keys.take_front(idx), // All prior keys.
550 [&](auto key) { commaSeparatedKeys += keyToStr(key); },
551 [&]() { commaSeparatedKeys += ","; });
553 auto diag = op->emitError() << "target op of failed DLTI query";
554 diag.attachNote(reportOp->getLoc())
555 << "got non-DLTI-queryable attribute upon looking up keys ["
556 << commaSeparatedKeys << "] at op";
558 return failure();
562 return currentAttr;
565 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
566 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
567 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
568 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
570 namespace {
571 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
572 public:
573 using DataLayoutDialectInterface::DataLayoutDialectInterface;
575 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
576 Location loc) const final {
577 StringRef entryName = entry.getKey().get<StringAttr>().strref();
578 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
579 auto value = dyn_cast<StringAttr>(entry.getValue());
580 if (value &&
581 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
582 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
583 return success();
584 return emitError(loc) << "'" << entryName
585 << "' data layout entry is expected to be either '"
586 << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
587 << DLTIDialect::kDataLayoutEndiannessLittle << "'";
589 if (entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
590 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
591 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
592 entryName == DLTIDialect::kDataLayoutStackAlignmentKey)
593 return success();
594 return emitError(loc) << "unknown data layout entry name: " << entryName;
597 } // namespace
599 void DLTIDialect::initialize() {
600 addAttributes<
601 #define GET_ATTRDEF_LIST
602 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
603 >();
604 addInterfaces<TargetDataLayoutInterface>();
607 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
608 NamedAttribute attr) {
609 if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
610 if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
611 return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
612 << "' is expected to be a #dlti.dl_spec attribute";
614 if (isa<ModuleOp>(op))
615 return detail::verifyDataLayoutOp(op);
616 return success();
619 if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
620 if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
621 return op->emitError()
622 << "'" << DLTIDialect::kTargetSystemDescAttrName
623 << "' is expected to be a #dlti.target_system_spec attribute";
625 return success();
628 if (attr.getName() == DLTIDialect::kMapAttrName) {
629 if (!llvm::isa<MapAttr>(attr.getValue())) {
630 return op->emitError() << "'" << DLTIDialect::kMapAttrName
631 << "' is expected to be a #dlti.map attribute";
633 return success();
636 return op->emitError() << "attribute '" << attr.getName().getValue()
637 << "' not supported by dialect";