MLIR  21.0.0git
DLTI.cpp
Go to the documentation of this file.
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 
10 #include "mlir/IR/Builders.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"
17 
18 #include "llvm/ADT/MapVector.h"
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 
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>
90  bool tryType = false,
91  bool allowEmpty = false) {
93  if (failed(parser.parseCommaSeparatedList(
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;
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.
138  bool allowTypes = true) {
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 {
166 public:
167  using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
168 
170  : entryKey(entryKey), value(value) {}
171 
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 
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 `>`
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 
255  return verifyEntries(emitError, entries);
256 }
257 
258 //===----------------------------------------------------------------------===//
259 // DataLayoutSpecAttr
260 //===----------------------------------------------------------------------===//
261 
262 LogicalResult
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
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 combineOneSpec(
297  DataLayoutSpecInterface spec,
298  llvm::MapVector<TypeID, DataLayoutEntryList> &entriesForType,
299  llvm::MapVector<StringAttr, DataLayoutEntryInterface> &entriesForID) {
300  // A missing spec should be fine.
301  if (!spec)
302  return success();
303 
304  llvm::MapVector<TypeID, DataLayoutEntryList> newEntriesForType;
305  llvm::MapVector<StringAttr, DataLayoutEntryInterface> newEntriesForID;
306  spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
307 
308  // Combine non-Type DL entries first so they are visible to the
309  // `type.areCompatible` method, allowing to query global properties.
310  for (const auto &kvp : newEntriesForID) {
311  StringAttr id = cast<StringAttr>(kvp.second.getKey());
312  Dialect *dialect = id.getReferencedDialect();
313  if (!entriesForID.count(id)) {
314  entriesForID[id] = kvp.second;
315  continue;
316  }
317 
318  // Attempt to combine the entries using the dialect interface. If the
319  // dialect is not loaded for some reason, use the default combinator
320  // that conservatively accepts identical entries only.
321  entriesForID[id] =
322  dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
323  entriesForID[id], kvp.second)
325  kvp.second);
326  if (!entriesForID[id])
327  return failure();
328  }
329 
330  // Try overwriting the old entries with the new ones.
331  for (auto &kvp : newEntriesForType) {
332  if (!entriesForType.count(kvp.first)) {
333  entriesForType[kvp.first] = std::move(kvp.second);
334  continue;
335  }
336 
337  Type typeSample = cast<Type>(kvp.second.front().getKey());
338  assert(&typeSample.getDialect() !=
339  typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
340  "unexpected data layout entry for built-in type");
341 
342  auto interface = cast<DataLayoutTypeInterface>(typeSample);
343  // TODO: Revisit this method and call once
344  // https://github.com/llvm/llvm-project/issues/130321 gets resolved.
345  if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
346  spec, entriesForID))
347  return failure();
348 
349  overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
350  }
351 
352  return success();
353 }
354 
355 DataLayoutSpecAttr
356 DataLayoutSpecAttr::combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
357  // Only combine with attributes of the same kind.
358  // TODO: reconsider this when the need arises.
359  if (any_of(specs, [](DataLayoutSpecInterface spec) {
360  return !llvm::isa<DataLayoutSpecAttr>(spec);
361  }))
362  return {};
363 
364  // Combine all specs in order, with `this` being the last one.
365  llvm::MapVector<TypeID, DataLayoutEntryList> entriesForType;
366  llvm::MapVector<StringAttr, DataLayoutEntryInterface> entriesForID;
367  for (DataLayoutSpecInterface spec : specs)
368  if (failed(combineOneSpec(spec, entriesForType, entriesForID)))
369  return nullptr;
370  if (failed(combineOneSpec(*this, entriesForType, entriesForID)))
371  return nullptr;
372 
373  // Rebuild the linear list of entries.
375  llvm::append_range(entries, llvm::make_second_range(entriesForID));
376  for (const auto &kvp : entriesForType)
377  llvm::append_range(entries, kvp.second);
378 
379  return DataLayoutSpecAttr::get(getContext(), entries);
380 }
381 
382 StringAttr
383 DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
384  return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
385 }
386 
387 StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
388  MLIRContext *context) const {
389  return Builder(context).getStringAttr(
390  DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
391 }
392 
393 StringAttr
394 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
395  return Builder(context).getStringAttr(
396  DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
397 }
398 
399 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
400  MLIRContext *context) const {
401  return Builder(context).getStringAttr(
402  DLTIDialect::kDataLayoutProgramMemorySpaceKey);
403 }
404 
405 StringAttr
406 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
407  return Builder(context).getStringAttr(
408  DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
409 }
410 
411 StringAttr
412 DataLayoutSpecAttr::getManglingModeIdentifier(MLIRContext *context) const {
413  return Builder(context).getStringAttr(
414  DLTIDialect::kDataLayoutManglingModeKey);
415 }
416 
417 StringAttr
418 DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
419  return Builder(context).getStringAttr(
420  DLTIDialect::kDataLayoutStackAlignmentKey);
421 }
422 
423 /// Parses an attribute with syntax:
424 /// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
425 /// entry-list ::= | entry | entry `,` entry-list
426 /// entry ::= ((type | quoted-string) = attr) | dl-entry-attr
428  return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type,
429  /*tryType=*/true,
430  /*allowEmpty=*/true);
431 }
432 
433 void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
434  printAngleBracketedEntries(printer, getEntries());
435 }
436 
437 //===----------------------------------------------------------------------===//
438 // TargetDeviceSpecAttr
439 //===----------------------------------------------------------------------===//
440 
441 LogicalResult
444  return verifyEntries(emitError, entries, /*allowTypes=*/false);
445 }
446 
447 /// Parses an attribute with syntax:
448 /// dev-spec-attr ::= `#dlti.` `target_device_spec` `<` entry-list `>`
449 /// entry-list ::= entry | entry `,` entry-list
450 /// entry ::= (quoted-string `=` attr) | dl-entry-attr
452  return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type);
453 }
454 
455 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
456  printAngleBracketedEntries(printer, getEntries());
457 }
458 
459 //===----------------------------------------------------------------------===//
460 // TargetSystemSpecAttr
461 //===----------------------------------------------------------------------===//
462 
463 LogicalResult
467 
468  for (const auto &entry : entries) {
469  auto deviceId =
470  llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
471  if (!deviceId)
472  return emitError() << "non-string key of DLTI system spec";
473 
474  if (auto targetDeviceSpec =
475  llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
477  targetDeviceSpec.getEntries())))
478  return failure(); // Assume sub-verifier outputted error message.
479  } else {
480  return emitError() << "value associated with key " << deviceId
481  << " is not a DLTI device spec";
482  }
483 
484  // Check that device IDs are unique across all entries.
485  if (!deviceIds.insert(deviceId).second)
486  return emitError() << "repeated device ID in dlti.target_system_spec: "
487  << deviceId;
488  }
489 
490  return success();
491 }
492 
493 /// Parses an attribute with syntax:
494 /// sys-spec-attr ::= `#dlti.` `target_system_spec` `<` entry-list `>`
495 /// entry-list ::= entry | entry `,` entry-list
496 /// entry ::= (quoted-string `=` dev-spec-attr) | dl-entry-attr
498  return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
499 }
500 
501 void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
502  printAngleBracketedEntries(printer, getEntries());
503 }
504 
505 //===----------------------------------------------------------------------===//
506 // DLTIDialect
507 //===----------------------------------------------------------------------===//
508 
509 /// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
510 /// attached to `op` or such an attr on as close as possible an ancestor. The
511 /// op the attribute is attached to is returned as well.
512 static std::pair<DLTIQueryInterface, Operation *>
514  DLTIQueryInterface queryable = {};
515 
516  // Search op and its ancestors for the first attached DLTIQueryInterface attr.
517  do {
518  for (NamedAttribute attr : op->getAttrs())
519  if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
520  break;
521  } while (!queryable && (op = op->getParentOp()));
522 
523  return std::pair(queryable, op);
524 }
525 
526 FailureOr<Attribute>
528  if (!op)
529  return failure();
530 
531  if (keys.empty()) {
532  if (emitError) {
533  auto diag = op->emitError() << "target op of failed DLTI query";
534  diag.attachNote(op->getLoc()) << "no keys provided to attempt query with";
535  }
536  return failure();
537  }
538 
539  auto [queryable, queryOp] = getClosestQueryable(op);
540  Operation *reportOp = (queryOp ? queryOp : op);
541 
542  if (!queryable) {
543  if (emitError) {
544  auto diag = op->emitError() << "target op of failed DLTI query";
545  diag.attachNote(reportOp->getLoc())
546  << "no DLTI-queryable attrs on target op or any of its ancestors";
547  }
548  return failure();
549  }
550 
551  Attribute currentAttr = queryable;
552  for (auto &&[idx, key] : llvm::enumerate(keys)) {
553  if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
554  auto maybeAttr = map.query(key);
555  if (failed(maybeAttr)) {
556  if (emitError) {
557  auto diag = op->emitError() << "target op of failed DLTI query";
558  diag.attachNote(reportOp->getLoc())
559  << "key " << keyToStr(key)
560  << " has no DLTI-mapping per attr: " << map;
561  }
562  return failure();
563  }
564  currentAttr = *maybeAttr;
565  } else {
566  if (emitError) {
567  std::string commaSeparatedKeys;
568  llvm::interleave(
569  keys.take_front(idx), // All prior keys.
570  [&](auto key) { commaSeparatedKeys += keyToStr(key); },
571  [&]() { commaSeparatedKeys += ","; });
572 
573  auto diag = op->emitError() << "target op of failed DLTI query";
574  diag.attachNote(reportOp->getLoc())
575  << "got non-DLTI-queryable attribute upon looking up keys ["
576  << commaSeparatedKeys << "] at op";
577  }
578  return failure();
579  }
580  }
581 
582  return currentAttr;
583 }
584 
585 FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
586  bool emitError) {
587  if (!op)
588  return failure();
589 
590  MLIRContext *ctx = op->getContext();
592  entryKeys.reserve(keys.size());
593  for (StringRef key : keys)
594  entryKeys.push_back(StringAttr::get(ctx, key));
595 
596  return dlti::query(op, entryKeys, emitError);
597 }
598 
599 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
600 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
601 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
602 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
603 
604 namespace {
605 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
606 public:
608 
609  LogicalResult verifyEntry(DataLayoutEntryInterface entry,
610  Location loc) const final {
611  StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
612  if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
613  auto value = dyn_cast<StringAttr>(entry.getValue());
614  if (value &&
615  (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
616  value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
617  return success();
618  return emitError(loc) << "'" << entryName
619  << "' data layout entry is expected to be either '"
620  << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
621  << DLTIDialect::kDataLayoutEndiannessLittle << "'";
622  }
623  if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
624  entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
625  entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
626  entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
627  entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
628  entryName == DLTIDialect::kDataLayoutManglingModeKey)
629  return success();
630  return emitError(loc) << "unknown data layout entry name: " << entryName;
631  }
632 };
633 } // namespace
634 
635 void DLTIDialect::initialize() {
636  addAttributes<
637 #define GET_ATTRDEF_LIST
638 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
639  >();
640  addInterfaces<TargetDataLayoutInterface>();
641 }
642 
643 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
644  NamedAttribute attr) {
645  if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
646  if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
647  return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
648  << "' is expected to be a #dlti.dl_spec attribute";
649  }
650  if (isa<ModuleOp>(op))
651  return detail::verifyDataLayoutOp(op);
652  return success();
653  }
654 
655  if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
656  if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
657  return op->emitError()
658  << "'" << DLTIDialect::kTargetSystemDescAttrName
659  << "' is expected to be a #dlti.target_system_spec attribute";
660  }
661  return success();
662  }
663 
664  if (attr.getName() == DLTIDialect::kMapAttrName) {
665  if (!llvm::isa<MapAttr>(attr.getValue())) {
666  return op->emitError() << "'" << DLTIDialect::kMapAttrName
667  << "' is expected to be a #dlti.map attribute";
668  }
669  return success();
670  }
671 
672  return op->emitError() << "attribute '" << attr.getName().getValue()
673  << "' not supported by dialect";
674 }
static LogicalResult verifyEntries(function_ref< InFlightDiagnostic()> emitError, ArrayRef< DataLayoutEntryInterface > entries, bool allowTypes=true)
Verify entries, with the option to disallow types as keys.
Definition: DLTI.cpp:136
static void printAngleBracketedEntries(AsmPrinter &os, T &&entries)
Pretty-print entries, each in key = value format, separated by commas.
Definition: DLTI.cpp:123
static std::pair< DLTIQueryInterface, Operation * > getClosestQueryable(Operation *op)
Retrieve the first DLTIQueryInterface-implementing attribute that is attached to op or such an attr o...
Definition: DLTI.cpp:513
static std::string keyToStr(DataLayoutEntryKey key)
Convert pointer-union keys to strings.
Definition: DLTI.cpp:113
static void overwriteDuplicateEntries(SmallVectorImpl< DataLayoutEntryInterface > &oldEntries, ArrayRef< DataLayoutEntryInterface > newEntries)
Given a list of old and a list of new entries, overwrites old entries with new ones if they have matc...
Definition: DLTI.cpp:272
static Attribute parseAngleBracketedEntries(AsmParser &parser, Type ty, bool tryType=false, bool allowEmpty=false)
Construct a requested attribute by parsing list of entries occurring within a pair of < and >,...
Definition: DLTI.cpp:89
static LogicalResult combineOneSpec(DataLayoutSpecInterface spec, llvm::MapVector< TypeID, DataLayoutEntryList > &entriesForType, llvm::MapVector< StringAttr, DataLayoutEntryInterface > &entriesForID)
Combines a data layout spec into the given lists of entries organized by type class and identifier,...
Definition: DLTI.cpp:296
static ParseResult parseKeyValuePair(AsmParser &parser, DataLayoutEntryInterface &entry, bool tryType=false)
Parse an entry which can either be of the form key = value or a #dlti.dl_entry attribute.
Definition: DLTI.cpp:40
static MLIRContext * getContext(OpFoldResult val)
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
This base class exposes generic asm parser hooks, usable across the various derived parsers.
@ LessGreater
<> brackets surrounding zero or more operands.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual OptionalParseResult parseOptionalType(Type &result)=0
Parse an optional type.
MLIRContext * getContext() const
Definition: AsmPrinter.cpp:73
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalString(std::string *string)=0
Parse a quoted string token if present.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
Base storage class appearing in an attribute.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:51
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:258
An interface to be implemented by dialects that can have identifiers in the data layout specification...
static DataLayoutEntryInterface defaultCombine(DataLayoutEntryInterface outer, DataLayoutEntryInterface inner)
Default implementation of entry combination that combines identical entries and returns null otherwis...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:38
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:66
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:164
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:55
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:179
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Definition: Operation.h:512
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:39
ParseResult value() const
Access the internal ParseResult value.
Definition: OpDefinition.h:52
bool has_value() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:49
This is a utility allocator used to allocate memory for instances of derived types.
T * allocate()
Allocate an instance of the provided type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
Dialect & getDialect() const
Get the dialect this type is registered to.
Definition: Types.h:107
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:35
DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
Definition: DLTI.cpp:169
bool operator==(const KeyTy &other) const
Definition: DLTI.cpp:178
std::pair< DataLayoutEntryKey, Attribute > KeyTy
Definition: DLTI.cpp:167
static DataLayoutEntryAttrStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
Definition: DLTI.cpp:173
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
LogicalResult verifyDataLayoutOp(Operation *op)
Verifies that the operation implementing the data layout interface, or a module operation,...
FailureOr< Attribute > query(Operation *op, ArrayRef< DataLayoutEntryKey > keys, bool emitError=false)
Perform a DLTI-query at op, recursively querying each key of keys on query interface-implementing att...
Definition: DLTI.cpp:527
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:20
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:424