xref: /llvm-project/mlir/lib/Dialect/DLTI/DLTI.cpp (revision 129f1001c3b1b5200de43917d53c0efbdf08f11f)
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 //===----------------------------------------------------------------------===//
8 
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"
18 
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/MathExtras.h"
22 
23 using namespace mlir;
24 
25 #include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
26 
27 #define GET_ATTRDEF_CLASSES
28 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
29 
30 #define DEBUG_TYPE "dlti"
31 
32 //===----------------------------------------------------------------------===//
33 // Common parsing utility functions.
34 //===----------------------------------------------------------------------===//
35 
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;
44 
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";
52 
53       if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
54         return failure();
55 
56       entry = DataLayoutEntryAttr::get(type, value);
57       return ParseResult::success();
58     }
59   }
60 
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.
66 
67     entry = DataLayoutEntryAttr::get(
68         StringAttr::get(parser.getContext(), ident), value);
69     return ParseResult::success();
70   }
71 
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.
77   }
78   return parser.emitError(parser.getCurrentLocation())
79          << "failed to parse DLTI entry";
80 }
81 
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 {};
98 
99   if (entries.empty() && !allowEmpty) {
100     parser.emitError(parser.getNameLoc()) << "no DLTI entries provided";
101     return {};
102   }
103 
104   return Attr::getChecked([&] { return parser.emitError(parser.getNameLoc()); },
105                           parser.getContext(), ArrayRef(entries));
106 }
107 
108 //===----------------------------------------------------------------------===//
109 // Common printing utility functions.
110 //===----------------------------------------------------------------------===//
111 
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;
119 }
120 
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();
127   });
128   os << ">";
129 }
130 
131 //===----------------------------------------------------------------------===//
132 // Common verifying utility functions.
133 //===----------------------------------------------------------------------===//
134 
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";
156   }
157   return success();
158 }
159 
160 //===----------------------------------------------------------------------===//
161 // DataLayoutEntryAttr
162 //===----------------------------------------------------------------------===//
163 namespace mlir {
164 namespace detail {
165 class DataLayoutEntryAttrStorage : public AttributeStorage {
166 public:
167   using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
168 
169   DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
170       : entryKey(entryKey), value(value) {}
171 
172   static DataLayoutEntryAttrStorage *
173   construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
174     return new (allocator.allocate<DataLayoutEntryAttrStorage>())
175         DataLayoutEntryAttrStorage(key.first, key.second);
176   }
177 
178   bool operator==(const KeyTy &other) const {
179     return other.first == entryKey && other.second == value;
180   }
181 
182   DataLayoutEntryKey entryKey;
183   Attribute value;
184 };
185 } // namespace detail
186 } // namespace mlir
187 
188 DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
189   return Base::get(key.getContext(), key, value);
190 }
191 
192 DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) {
193   return Base::get(key.getContext(), key, value);
194 }
195 
196 DataLayoutEntryKey DataLayoutEntryAttr::getKey() const {
197   return getImpl()->entryKey;
198 }
199 
200 Attribute DataLayoutEntryAttr::getValue() const { return getImpl()->value; }
201 
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 {};
208 
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 {};
220     }
221   }
222 
223   Attribute value;
224   if (failed(parser.parseComma()) || failed(parser.parseAttribute(value)) ||
225       failed(parser.parseGreater()))
226     return {};
227 
228   return typeKey ? get(typeKey, value)
229                  : get(parser.getBuilder().getStringAttr(identifier), value);
230 }
231 
232 void DataLayoutEntryAttr::print(AsmPrinter &printer) const {
233   printer << "<" << keyToStr(getKey()) << ", " << getValue() << ">";
234 }
235 
236 //===----------------------------------------------------------------------===//
237 // DLTIMapAttr
238 //===----------------------------------------------------------------------===//
239 
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);
247 }
248 
249 void MapAttr::print(AsmPrinter &printer) const {
250   printAngleBracketedEntries(printer, getEntries());
251 }
252 
253 LogicalResult MapAttr::verify(function_ref<InFlightDiagnostic()> emitError,
254                               ArrayRef<DataLayoutEntryInterface> entries) {
255   return verifyEntries(emitError, entries);
256 }
257 
258 //===----------------------------------------------------------------------===//
259 // DataLayoutSpecAttr
260 //===----------------------------------------------------------------------===//
261 
262 LogicalResult
263 DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
264                            ArrayRef<DataLayoutEntryInterface> entries) {
265   return verifyEntries(emitError, entries);
266 }
267 
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;
286       }
287     }
288     if (!replaced)
289       oldEntries.push_back(entry);
290   }
291 }
292 
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();
303 
304   DenseMap<TypeID, DataLayoutEntryList> newEntriesForType;
305   DenseMap<StringAttr, DataLayoutEntryInterface> newEntriesForID;
306   spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
307 
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;
313     }
314 
315     Type typeSample = cast<Type>(kvp.second.front().getKey());
316     assert(&typeSample.getDialect() !=
317                typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
318            "unexpected data layout entry for built-in type");
319 
320     auto interface = cast<DataLayoutTypeInterface>(typeSample);
321     if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second))
322       return failure();
323 
324     overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
325   }
326 
327   for (const auto &kvp : newEntriesForID) {
328     StringAttr id = cast<StringAttr>(kvp.second.getKey());
329     Dialect *dialect = id.getReferencedDialect();
330     if (!entriesForID.count(id)) {
331       entriesForID[id] = kvp.second;
332       continue;
333     }
334 
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();
345   }
346 
347   return success();
348 }
349 
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);
356       }))
357     return {};
358 
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;
367 
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());
373 
374   return DataLayoutSpecAttr::get(getContext(), entries);
375 }
376 
377 StringAttr
378 DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
379   return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
380 }
381 
382 StringAttr
383 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
384   return Builder(context).getStringAttr(
385       DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
386 }
387 
388 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
389     MLIRContext *context) const {
390   return Builder(context).getStringAttr(
391       DLTIDialect::kDataLayoutProgramMemorySpaceKey);
392 }
393 
394 StringAttr
395 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
396   return Builder(context).getStringAttr(
397       DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
398 }
399 
400 StringAttr
401 DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
402   return Builder(context).getStringAttr(
403       DLTIDialect::kDataLayoutStackAlignmentKey);
404 }
405 
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);
414 }
415 
416 void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
417   printAngleBracketedEntries(printer, getEntries());
418 }
419 
420 //===----------------------------------------------------------------------===//
421 // TargetDeviceSpecAttr
422 //===----------------------------------------------------------------------===//
423 
424 LogicalResult
425 TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
426                              ArrayRef<DataLayoutEntryInterface> entries) {
427   return verifyEntries(emitError, entries, /*allowTypes=*/false);
428 }
429 
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);
436 }
437 
438 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
439   printAngleBracketedEntries(printer, getEntries());
440 }
441 
442 //===----------------------------------------------------------------------===//
443 // TargetSystemSpecAttr
444 //===----------------------------------------------------------------------===//
445 
446 LogicalResult
447 TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
448                              ArrayRef<DataLayoutEntryInterface> entries) {
449   DenseSet<TargetSystemSpecInterface::DeviceID> deviceIds;
450 
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";
456 
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";
465     }
466 
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;
471   }
472 
473   return success();
474 }
475 
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);
482 }
483 
484 void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
485   printAngleBracketedEntries(printer, getEntries());
486 }
487 
488 //===----------------------------------------------------------------------===//
489 // DLTIDialect
490 //===----------------------------------------------------------------------===//
491 
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 = {};
498 
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()));
505 
506   return std::pair(queryable, op);
507 }
508 
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";
515     }
516     return failure();
517   }
518 
519   auto [queryable, queryOp] = getClosestQueryable(op);
520   Operation *reportOp = (queryOp ? queryOp : op);
521 
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";
527     }
528     return failure();
529   }
530 
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;
541         }
542         return failure();
543       }
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 += ","; });
552 
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";
557       }
558       return failure();
559     }
560   }
561 
562   return currentAttr;
563 }
564 
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;
569 
570 namespace {
571 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
572 public:
573   using DataLayoutDialectInterface::DataLayoutDialectInterface;
574 
575   LogicalResult verifyEntry(DataLayoutEntryInterface entry,
576                             Location loc) const final {
577     StringRef entryName = cast<StringAttr>(entry.getKey()).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 << "'";
588     }
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;
595   }
596 };
597 } // namespace
598 
599 void DLTIDialect::initialize() {
600   addAttributes<
601 #define GET_ATTRDEF_LIST
602 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
603       >();
604   addInterfaces<TargetDataLayoutInterface>();
605 }
606 
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";
613     }
614     if (isa<ModuleOp>(op))
615       return detail::verifyDataLayoutOp(op);
616     return success();
617   }
618 
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";
624     }
625     return success();
626   }
627 
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";
632     }
633     return success();
634   }
635 
636   return op->emitError() << "attribute '" << attr.getName().getValue()
637                          << "' not supported by dialect";
638 }
639