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 StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
424  MLIRContext *context) const {
425  return Builder(context).getStringAttr(
426  DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
427 }
428 
429 StringAttr
430 DataLayoutSpecAttr::getLegalIntWidthsIdentifier(MLIRContext *context) const {
431  return Builder(context).getStringAttr(
432  DLTIDialect::kDataLayoutLegalIntWidthsKey);
433 }
434 
435 /// Parses an attribute with syntax:
436 /// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
437 /// entry-list ::= | entry | entry `,` entry-list
438 /// entry ::= ((type | quoted-string) = attr) | dl-entry-attr
440  return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type,
441  /*tryType=*/true,
442  /*allowEmpty=*/true);
443 }
444 
445 void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
446  printAngleBracketedEntries(printer, getEntries());
447 }
448 
449 //===----------------------------------------------------------------------===//
450 // TargetDeviceSpecAttr
451 //===----------------------------------------------------------------------===//
452 
453 LogicalResult
456  return verifyEntries(emitError, entries, /*allowTypes=*/false);
457 }
458 
459 /// Parses an attribute with syntax:
460 /// dev-spec-attr ::= `#dlti.` `target_device_spec` `<` entry-list `>`
461 /// entry-list ::= entry | entry `,` entry-list
462 /// entry ::= (quoted-string `=` attr) | dl-entry-attr
464  return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type);
465 }
466 
467 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
468  printAngleBracketedEntries(printer, getEntries());
469 }
470 
471 //===----------------------------------------------------------------------===//
472 // TargetSystemSpecAttr
473 //===----------------------------------------------------------------------===//
474 
475 LogicalResult
479 
480  for (const auto &entry : entries) {
481  auto deviceId =
482  llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
483  if (!deviceId)
484  return emitError() << "non-string key of DLTI system spec";
485 
486  if (auto targetDeviceSpec =
487  llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
489  targetDeviceSpec.getEntries())))
490  return failure(); // Assume sub-verifier outputted error message.
491  } else {
492  return emitError() << "value associated with key " << deviceId
493  << " is not a DLTI device spec";
494  }
495 
496  // Check that device IDs are unique across all entries.
497  if (!deviceIds.insert(deviceId).second)
498  return emitError() << "repeated device ID in dlti.target_system_spec: "
499  << deviceId;
500  }
501 
502  return success();
503 }
504 
505 /// Parses an attribute with syntax:
506 /// sys-spec-attr ::= `#dlti.` `target_system_spec` `<` entry-list `>`
507 /// entry-list ::= entry | entry `,` entry-list
508 /// entry ::= (quoted-string `=` dev-spec-attr) | dl-entry-attr
510  return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
511 }
512 
513 void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
514  printAngleBracketedEntries(printer, getEntries());
515 }
516 
517 //===----------------------------------------------------------------------===//
518 // DLTIDialect
519 //===----------------------------------------------------------------------===//
520 
521 /// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
522 /// attached to `op` or such an attr on as close as possible an ancestor. The
523 /// op the attribute is attached to is returned as well.
524 static std::pair<DLTIQueryInterface, Operation *>
526  DLTIQueryInterface queryable = {};
527 
528  // Search op and its ancestors for the first attached DLTIQueryInterface attr.
529  do {
530  for (NamedAttribute attr : op->getAttrs())
531  if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
532  break;
533  } while (!queryable && (op = op->getParentOp()));
534 
535  return std::pair(queryable, op);
536 }
537 
538 FailureOr<Attribute>
540  if (!op)
541  return failure();
542 
543  if (keys.empty()) {
544  if (emitError) {
545  auto diag = op->emitError() << "target op of failed DLTI query";
546  diag.attachNote(op->getLoc()) << "no keys provided to attempt query with";
547  }
548  return failure();
549  }
550 
551  auto [queryable, queryOp] = getClosestQueryable(op);
552  Operation *reportOp = (queryOp ? queryOp : op);
553 
554  if (!queryable) {
555  if (emitError) {
556  auto diag = op->emitError() << "target op of failed DLTI query";
557  diag.attachNote(reportOp->getLoc())
558  << "no DLTI-queryable attrs on target op or any of its ancestors";
559  }
560  return failure();
561  }
562 
563  Attribute currentAttr = queryable;
564  for (auto &&[idx, key] : llvm::enumerate(keys)) {
565  if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
566  auto maybeAttr = map.query(key);
567  if (failed(maybeAttr)) {
568  if (emitError) {
569  auto diag = op->emitError() << "target op of failed DLTI query";
570  diag.attachNote(reportOp->getLoc())
571  << "key " << keyToStr(key)
572  << " has no DLTI-mapping per attr: " << map;
573  }
574  return failure();
575  }
576  currentAttr = *maybeAttr;
577  } else {
578  if (emitError) {
579  std::string commaSeparatedKeys;
580  llvm::interleave(
581  keys.take_front(idx), // All prior keys.
582  [&](auto key) { commaSeparatedKeys += keyToStr(key); },
583  [&]() { commaSeparatedKeys += ","; });
584 
585  auto diag = op->emitError() << "target op of failed DLTI query";
586  diag.attachNote(reportOp->getLoc())
587  << "got non-DLTI-queryable attribute upon looking up keys ["
588  << commaSeparatedKeys << "] at op";
589  }
590  return failure();
591  }
592  }
593 
594  return currentAttr;
595 }
596 
597 FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
598  bool emitError) {
599  if (!op)
600  return failure();
601 
602  MLIRContext *ctx = op->getContext();
604  entryKeys.reserve(keys.size());
605  for (StringRef key : keys)
606  entryKeys.push_back(StringAttr::get(ctx, key));
607 
608  return dlti::query(op, entryKeys, emitError);
609 }
610 
611 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
612 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
613 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
614 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
615 
616 namespace {
617 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
618 public:
620 
621  LogicalResult verifyEntry(DataLayoutEntryInterface entry,
622  Location loc) const final {
623  StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
624  if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
625  auto value = dyn_cast<StringAttr>(entry.getValue());
626  if (value &&
627  (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
628  value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
629  return success();
630  return emitError(loc) << "'" << entryName
631  << "' data layout entry is expected to be either '"
632  << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
633  << DLTIDialect::kDataLayoutEndiannessLittle << "'";
634  }
635  if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
636  entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
637  entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
638  entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
639  entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
640  entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
641  entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
642  entryName == DLTIDialect::kDataLayoutManglingModeKey)
643  return success();
644  return emitError(loc) << "unknown data layout entry name: " << entryName;
645  }
646 };
647 } // namespace
648 
649 void DLTIDialect::initialize() {
650  addAttributes<
651 #define GET_ATTRDEF_LIST
652 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
653  >();
654  addInterfaces<TargetDataLayoutInterface>();
655 }
656 
657 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
658  NamedAttribute attr) {
659  if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
660  if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
661  return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
662  << "' is expected to be a #dlti.dl_spec attribute";
663  }
664  if (isa<ModuleOp>(op))
665  return detail::verifyDataLayoutOp(op);
666  return success();
667  }
668 
669  if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
670  if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
671  return op->emitError()
672  << "'" << DLTIDialect::kTargetSystemDescAttrName
673  << "' is expected to be a #dlti.target_system_spec attribute";
674  }
675  return success();
676  }
677 
678  if (attr.getName() == DLTIDialect::kMapAttrName) {
679  if (!llvm::isa<MapAttr>(attr.getValue())) {
680  return op->emitError() << "'" << DLTIDialect::kMapAttrName
681  << "' is expected to be a #dlti.map attribute";
682  }
683  return success();
684  }
685 
686  return op->emitError() << "attribute '" << attr.getName().getValue()
687  << "' not supported by dialect";
688 }
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:525
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:50
StringAttr getStringAttr(const Twine &bytes)
Definition: Builders.cpp:260
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:76
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:539
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:22
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:423