MLIR  22.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 
21 using namespace mlir;
22 
23 #include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
24 
25 #define GET_ATTRDEF_CLASSES
26 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
27 
28 #define DEBUG_TYPE "dlti"
29 
30 //===----------------------------------------------------------------------===//
31 // Common parsing utility functions.
32 //===----------------------------------------------------------------------===//
33 
34 /// Parse an entry which can either be of the form `key = value` or a
35 /// #dlti.dl_entry attribute. When `tryType=true` the key can be a type,
36 /// otherwise only quoted strings are allowed. The grammar is as follows:
37 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
38 static ParseResult parseKeyValuePair(AsmParser &parser,
39  DataLayoutEntryInterface &entry,
40  bool tryType = false) {
41  Attribute value;
42 
43  if (tryType) {
44  Type type;
45  OptionalParseResult parsedType = parser.parseOptionalType(type);
46  if (parsedType.has_value()) {
47  if (failed(parsedType.value()))
48  return parser.emitError(parser.getCurrentLocation())
49  << "error while parsing type DLTI key";
50 
51  if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
52  return failure();
53 
54  entry = DataLayoutEntryAttr::get(type, value);
55  return ParseResult::success();
56  }
57  }
58 
59  std::string ident;
60  OptionalParseResult parsedStr = parser.parseOptionalString(&ident);
61  if (parsedStr.has_value() && succeeded(parsedStr.value())) {
62  if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
63  return failure(); // Assume that an error has already been emitted.
64 
66  StringAttr::get(parser.getContext(), ident), value);
67  return ParseResult::success();
68  }
69 
70  OptionalParseResult parsedEntry = parser.parseAttribute(entry);
71  if (parsedEntry.has_value()) {
72  if (succeeded(parsedEntry.value()))
73  return parsedEntry.value();
74  return failure(); // Assume that an error has already been emitted.
75  }
76  return parser.emitError(parser.getCurrentLocation())
77  << "failed to parse DLTI entry";
78 }
79 
80 /// Construct a requested attribute by parsing list of entries occurring within
81 /// a pair of `<` and `>`, optionally allow types as keys and an empty list.
82 /// The grammar is as follows:
83 /// bracketed-entry-list ::=`<` entry-list `>`
84 /// entry-list ::= | entry | entry `,` entry-list
85 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
86 template <class Attr>
88  bool tryType = false,
89  bool allowEmpty = false) {
91  if (failed(parser.parseCommaSeparatedList(
93  return parseKeyValuePair(parser, entries.emplace_back(), tryType);
94  })))
95  return {};
96 
97  if (entries.empty() && !allowEmpty) {
98  parser.emitError(parser.getNameLoc()) << "no DLTI entries provided";
99  return {};
100  }
101 
102  return Attr::getChecked([&] { return parser.emitError(parser.getNameLoc()); },
103  parser.getContext(), ArrayRef(entries));
104 }
105 
106 //===----------------------------------------------------------------------===//
107 // Common printing utility functions.
108 //===----------------------------------------------------------------------===//
109 
110 /// Convert pointer-union keys to strings.
111 static std::string keyToStr(DataLayoutEntryKey key) {
112  std::string buf;
114  .Case<StringAttr, Type>( // The only two kinds of key we know of.
115  [&](auto key) { llvm::raw_string_ostream(buf) << key; });
116  return buf;
117 }
118 
119 /// Pretty-print entries, each in `key = value` format, separated by commas.
120 template <class T>
121 static void printAngleBracketedEntries(AsmPrinter &os, T &&entries) {
122  os << "<";
123  llvm::interleaveComma(std::forward<T>(entries), os, [&](auto entry) {
124  os << keyToStr(entry.getKey()) << " = " << entry.getValue();
125  });
126  os << ">";
127 }
128 
129 //===----------------------------------------------------------------------===//
130 // Common verifying utility functions.
131 //===----------------------------------------------------------------------===//
132 
133 /// Verify entries, with the option to disallow types as keys.
136  bool allowTypes = true) {
138  for (DataLayoutEntryInterface entry : entries) {
139  if (!entry)
140  return emitError() << "contained invalid DLTI entry";
141  DataLayoutEntryKey key = entry.getKey();
142  if (key.isNull())
143  return emitError() << "contained invalid DLTI key";
144  if (!allowTypes && dyn_cast<Type>(key))
145  return emitError() << "type as DLTI key is not allowed";
146  if (auto strKey = dyn_cast<StringAttr>(key))
147  if (strKey.getValue().empty())
148  return emitError() << "empty string as DLTI key is not allowed";
149  if (!keys.insert(key).second)
150  return emitError() << "repeated DLTI key: " << keyToStr(key);
151  if (!entry.getValue())
152  return emitError() << "value associated to DLTI key " << keyToStr(key)
153  << " is invalid";
154  }
155  return success();
156 }
157 
158 //===----------------------------------------------------------------------===//
159 // DataLayoutEntryAttr
160 //===----------------------------------------------------------------------===//
161 namespace mlir {
162 namespace detail {
164 public:
165  using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
166 
168  : entryKey(entryKey), value(value) {}
169 
171  construct(AttributeStorageAllocator &allocator, const KeyTy &key) {
172  return new (allocator.allocate<DataLayoutEntryAttrStorage>())
173  DataLayoutEntryAttrStorage(key.first, key.second);
174  }
175 
176  bool operator==(const KeyTy &other) const {
177  return other.first == entryKey && other.second == value;
178  }
179 
182 };
183 } // namespace detail
184 } // namespace mlir
185 
186 DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
187  return Base::get(key.getContext(), key, value);
188 }
189 
190 DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) {
191  return Base::get(key.getContext(), key, value);
192 }
193 
194 DataLayoutEntryKey DataLayoutEntryAttr::getKey() const {
195  return getImpl()->entryKey;
196 }
197 
198 Attribute DataLayoutEntryAttr::getValue() const { return getImpl()->value; }
199 
200 /// Parses an attribute with syntax:
201 /// dl-entry-attr ::= `#dlti.` `dl_entry` `<` (type | quoted-string) `,`
202 /// attr `>`
204  if (failed(parser.parseLess()))
205  return {};
206 
207  Type typeKey = nullptr;
208  std::string identifier;
209  SMLoc idLoc = parser.getCurrentLocation();
210  OptionalParseResult parsedType = parser.parseOptionalType(typeKey);
211  if (parsedType.has_value() && failed(parsedType.value()))
212  return {};
213  if (!parsedType.has_value()) {
214  OptionalParseResult parsedString = parser.parseOptionalString(&identifier);
215  if (!parsedString.has_value() || failed(parsedString.value())) {
216  parser.emitError(idLoc) << "expected a type or a quoted string";
217  return {};
218  }
219  }
220 
221  Attribute value;
222  if (failed(parser.parseComma()) || failed(parser.parseAttribute(value)) ||
223  failed(parser.parseGreater()))
224  return {};
225 
226  return typeKey ? get(typeKey, value)
227  : get(parser.getBuilder().getStringAttr(identifier), value);
228 }
229 
230 void DataLayoutEntryAttr::print(AsmPrinter &printer) const {
231  printer << "<" << keyToStr(getKey()) << ", " << getValue() << ">";
232 }
233 
234 //===----------------------------------------------------------------------===//
235 // DLTIMapAttr
236 //===----------------------------------------------------------------------===//
237 
238 /// Parses an attribute with syntax:
239 /// map-attr ::= `#dlti.` `map` `<` entry-list `>`
240 /// entry-list ::= entry | entry `,` entry-list
241 /// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
242 Attribute MapAttr::parse(AsmParser &parser, Type type) {
243  return parseAngleBracketedEntries<MapAttr>(parser, type, /*tryType=*/true,
244  /*allowEmpty=*/true);
245 }
246 
247 void MapAttr::print(AsmPrinter &printer) const {
248  printAngleBracketedEntries(printer, getEntries());
249 }
250 
253  return verifyEntries(emitError, entries);
254 }
255 
256 //===----------------------------------------------------------------------===//
257 // DataLayoutSpecAttr
258 //===----------------------------------------------------------------------===//
259 
260 LogicalResult
263  return verifyEntries(emitError, entries);
264 }
265 
266 /// Given a list of old and a list of new entries, overwrites old entries with
267 /// new ones if they have matching keys, appends new entries to the old entry
268 /// list otherwise.
269 static void
272  unsigned oldEntriesSize = oldEntries.size();
273  for (DataLayoutEntryInterface entry : newEntries) {
274  // We expect a small (dozens) number of entries, so it is practically
275  // cheaper to iterate over the list linearly rather than to create an
276  // auxiliary hashmap to avoid duplication. Also note that we never need to
277  // check for duplicate keys the values that were added from `newEntries`.
278  bool replaced = false;
279  for (unsigned i = 0; i < oldEntriesSize; ++i) {
280  if (oldEntries[i].getKey() == entry.getKey()) {
281  oldEntries[i] = entry;
282  replaced = true;
283  break;
284  }
285  }
286  if (!replaced)
287  oldEntries.push_back(entry);
288  }
289 }
290 
291 /// Combines a data layout spec into the given lists of entries organized by
292 /// type class and identifier, overwriting them if necessary. Fails to combine
293 /// if the two entries with identical keys are not compatible.
294 static LogicalResult combineOneSpec(
295  DataLayoutSpecInterface spec,
296  llvm::MapVector<TypeID, DataLayoutEntryList> &entriesForType,
297  llvm::MapVector<StringAttr, DataLayoutEntryInterface> &entriesForID) {
298  // A missing spec should be fine.
299  if (!spec)
300  return success();
301 
302  llvm::MapVector<TypeID, DataLayoutEntryList> newEntriesForType;
303  llvm::MapVector<StringAttr, DataLayoutEntryInterface> newEntriesForID;
304  spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
305 
306  // Combine non-Type DL entries first so they are visible to the
307  // `type.areCompatible` method, allowing to query global properties.
308  for (const auto &kvp : newEntriesForID) {
309  StringAttr id = cast<StringAttr>(kvp.second.getKey());
310  Dialect *dialect = id.getReferencedDialect();
311  if (!entriesForID.count(id)) {
312  entriesForID[id] = kvp.second;
313  continue;
314  }
315 
316  // Attempt to combine the entries using the dialect interface. If the
317  // dialect is not loaded for some reason, use the default combinator
318  // that conservatively accepts identical entries only.
319  entriesForID[id] =
320  dialect ? cast<DataLayoutDialectInterface>(dialect)->combine(
321  entriesForID[id], kvp.second)
323  kvp.second);
324  if (!entriesForID[id])
325  return failure();
326  }
327 
328  // Try overwriting the old entries with the new ones.
329  for (auto &kvp : newEntriesForType) {
330  if (!entriesForType.count(kvp.first)) {
331  entriesForType[kvp.first] = std::move(kvp.second);
332  continue;
333  }
334 
335  Type typeSample = cast<Type>(kvp.second.front().getKey());
336  assert(&typeSample.getDialect() !=
337  typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
338  "unexpected data layout entry for built-in type");
339 
340  auto interface = cast<DataLayoutTypeInterface>(typeSample);
341  // TODO: Revisit this method and call once
342  // https://github.com/llvm/llvm-project/issues/130321 gets resolved.
343  if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
344  spec, entriesForID))
345  return failure();
346 
347  overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
348  }
349 
350  return success();
351 }
352 
353 DataLayoutSpecAttr
354 DataLayoutSpecAttr::combineWith(ArrayRef<DataLayoutSpecInterface> specs) const {
355  // Only combine with attributes of the same kind.
356  // TODO: reconsider this when the need arises.
357  if (any_of(specs, [](DataLayoutSpecInterface spec) {
358  return !llvm::isa<DataLayoutSpecAttr>(spec);
359  }))
360  return {};
361 
362  // Combine all specs in order, with `this` being the last one.
363  llvm::MapVector<TypeID, DataLayoutEntryList> entriesForType;
364  llvm::MapVector<StringAttr, DataLayoutEntryInterface> entriesForID;
365  for (DataLayoutSpecInterface spec : specs)
366  if (failed(combineOneSpec(spec, entriesForType, entriesForID)))
367  return nullptr;
368  if (failed(combineOneSpec(*this, entriesForType, entriesForID)))
369  return nullptr;
370 
371  // Rebuild the linear list of entries.
373  llvm::append_range(entries, llvm::make_second_range(entriesForID));
374  for (const auto &kvp : entriesForType)
375  llvm::append_range(entries, kvp.second);
376 
377  return DataLayoutSpecAttr::get(getContext(), entries);
378 }
379 
380 StringAttr
381 DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
382  return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
383 }
384 
385 StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
386  MLIRContext *context) const {
387  return Builder(context).getStringAttr(
388  DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
389 }
390 
391 StringAttr
392 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
393  return Builder(context).getStringAttr(
394  DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
395 }
396 
397 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
398  MLIRContext *context) const {
399  return Builder(context).getStringAttr(
400  DLTIDialect::kDataLayoutProgramMemorySpaceKey);
401 }
402 
403 StringAttr
404 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
405  return Builder(context).getStringAttr(
406  DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
407 }
408 
409 StringAttr
410 DataLayoutSpecAttr::getManglingModeIdentifier(MLIRContext *context) const {
411  return Builder(context).getStringAttr(
412  DLTIDialect::kDataLayoutManglingModeKey);
413 }
414 
415 StringAttr
416 DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
417  return Builder(context).getStringAttr(
418  DLTIDialect::kDataLayoutStackAlignmentKey);
419 }
420 
421 StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
422  MLIRContext *context) const {
423  return Builder(context).getStringAttr(
424  DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
425 }
426 
427 StringAttr
428 DataLayoutSpecAttr::getLegalIntWidthsIdentifier(MLIRContext *context) const {
429  return Builder(context).getStringAttr(
430  DLTIDialect::kDataLayoutLegalIntWidthsKey);
431 }
432 
433 /// Parses an attribute with syntax:
434 /// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
435 /// entry-list ::= | entry | entry `,` entry-list
436 /// entry ::= ((type | quoted-string) = attr) | dl-entry-attr
438  return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type,
439  /*tryType=*/true,
440  /*allowEmpty=*/true);
441 }
442 
443 void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
444  printAngleBracketedEntries(printer, getEntries());
445 }
446 
447 //===----------------------------------------------------------------------===//
448 // TargetDeviceSpecAttr
449 //===----------------------------------------------------------------------===//
450 
451 LogicalResult
454  return verifyEntries(emitError, entries, /*allowTypes=*/false);
455 }
456 
457 /// Parses an attribute with syntax:
458 /// dev-spec-attr ::= `#dlti.` `target_device_spec` `<` entry-list `>`
459 /// entry-list ::= entry | entry `,` entry-list
460 /// entry ::= (quoted-string `=` attr) | dl-entry-attr
462  return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type);
463 }
464 
465 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
466  printAngleBracketedEntries(printer, getEntries());
467 }
468 
469 //===----------------------------------------------------------------------===//
470 // TargetSystemSpecAttr
471 //===----------------------------------------------------------------------===//
472 
473 LogicalResult
477 
478  for (const auto &entry : entries) {
479  auto deviceId =
480  llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
481  if (!deviceId)
482  return emitError() << "non-string key of DLTI system spec";
483 
484  if (auto targetDeviceSpec =
485  llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) {
487  targetDeviceSpec.getEntries())))
488  return failure(); // Assume sub-verifier outputted error message.
489  } else {
490  return emitError() << "value associated with key " << deviceId
491  << " is not a DLTI device spec";
492  }
493 
494  // Check that device IDs are unique across all entries.
495  if (!deviceIds.insert(deviceId).second)
496  return emitError() << "repeated device ID in dlti.target_system_spec: "
497  << deviceId;
498  }
499 
500  return success();
501 }
502 
503 /// Parses an attribute with syntax:
504 /// sys-spec-attr ::= `#dlti.` `target_system_spec` `<` entry-list `>`
505 /// entry-list ::= entry | entry `,` entry-list
506 /// entry ::= (quoted-string `=` dev-spec-attr) | dl-entry-attr
508  return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
509 }
510 
511 void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
512  printAngleBracketedEntries(printer, getEntries());
513 }
514 
515 //===----------------------------------------------------------------------===//
516 // DLTIDialect
517 //===----------------------------------------------------------------------===//
518 
519 /// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
520 /// attached to `op` or such an attr on as close as possible an ancestor. The
521 /// op the attribute is attached to is returned as well.
522 static std::pair<DLTIQueryInterface, Operation *>
524  DLTIQueryInterface queryable = {};
525 
526  // Search op and its ancestors for the first attached DLTIQueryInterface attr.
527  do {
528  for (NamedAttribute attr : op->getAttrs())
529  if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
530  break;
531  } while (!queryable && (op = op->getParentOp()));
532 
533  return std::pair(queryable, op);
534 }
535 
536 FailureOr<Attribute>
538  if (!op)
539  return failure();
540 
541  if (keys.empty()) {
542  if (emitError) {
543  auto diag = op->emitError() << "target op of failed DLTI query";
544  diag.attachNote(op->getLoc()) << "no keys provided to attempt query with";
545  }
546  return failure();
547  }
548 
549  auto [queryable, queryOp] = getClosestQueryable(op);
550  Operation *reportOp = (queryOp ? queryOp : op);
551 
552  if (!queryable) {
553  if (emitError) {
554  auto diag = op->emitError() << "target op of failed DLTI query";
555  diag.attachNote(reportOp->getLoc())
556  << "no DLTI-queryable attrs on target op or any of its ancestors";
557  }
558  return failure();
559  }
560 
561  Attribute currentAttr = queryable;
562  for (auto &&[idx, key] : llvm::enumerate(keys)) {
563  if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
564  auto maybeAttr = map.query(key);
565  if (failed(maybeAttr)) {
566  if (emitError) {
567  auto diag = op->emitError() << "target op of failed DLTI query";
568  diag.attachNote(reportOp->getLoc())
569  << "key " << keyToStr(key)
570  << " has no DLTI-mapping per attr: " << map;
571  }
572  return failure();
573  }
574  currentAttr = *maybeAttr;
575  } else {
576  if (emitError) {
577  std::string commaSeparatedKeys;
578  llvm::interleave(
579  keys.take_front(idx), // All prior keys.
580  [&](auto key) { commaSeparatedKeys += keyToStr(key); },
581  [&]() { commaSeparatedKeys += ","; });
582 
583  auto diag = op->emitError() << "target op of failed DLTI query";
584  diag.attachNote(reportOp->getLoc())
585  << "got non-DLTI-queryable attribute upon looking up keys ["
586  << commaSeparatedKeys << "] at op";
587  }
588  return failure();
589  }
590  }
591 
592  return currentAttr;
593 }
594 
595 FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
596  bool emitError) {
597  if (!op)
598  return failure();
599 
600  MLIRContext *ctx = op->getContext();
602  entryKeys.reserve(keys.size());
603  for (StringRef key : keys)
604  entryKeys.push_back(StringAttr::get(ctx, key));
605 
606  return dlti::query(op, entryKeys, emitError);
607 }
608 
609 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
610 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
611 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
612 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
613 
614 namespace {
615 class TargetDataLayoutInterface : public DataLayoutDialectInterface {
616 public:
618 
619  LogicalResult verifyEntry(DataLayoutEntryInterface entry,
620  Location loc) const final {
621  StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
622  if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
623  auto value = dyn_cast<StringAttr>(entry.getValue());
624  if (value &&
625  (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
626  value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
627  return success();
628  return emitError(loc) << "'" << entryName
629  << "' data layout entry is expected to be either '"
630  << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
631  << DLTIDialect::kDataLayoutEndiannessLittle << "'";
632  }
633  if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
634  entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
635  entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
636  entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
637  entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
638  entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
639  entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
640  entryName == DLTIDialect::kDataLayoutManglingModeKey)
641  return success();
642  return emitError(loc) << "unknown data layout entry name: " << entryName;
643  }
644 };
645 } // namespace
646 
647 void DLTIDialect::initialize() {
648  addAttributes<
649 #define GET_ATTRDEF_LIST
650 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
651  >();
652  addInterfaces<TargetDataLayoutInterface>();
653 }
654 
655 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
656  NamedAttribute attr) {
657  if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
658  if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
659  return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
660  << "' is expected to be a #dlti.dl_spec attribute";
661  }
662  if (isa<ModuleOp>(op))
663  return detail::verifyDataLayoutOp(op);
664  return success();
665  }
666 
667  if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
668  if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
669  return op->emitError()
670  << "'" << DLTIDialect::kTargetSystemDescAttrName
671  << "' is expected to be a #dlti.target_system_spec attribute";
672  }
673  return success();
674  }
675 
676  if (attr.getName() == DLTIDialect::kMapAttrName) {
677  if (!llvm::isa<MapAttr>(attr.getValue())) {
678  return op->emitError() << "'" << DLTIDialect::kMapAttrName
679  << "' is expected to be a #dlti.map attribute";
680  }
681  return success();
682  }
683 
684  return op->emitError() << "attribute '" << attr.getName().getValue()
685  << "' not supported by dialect";
686 }
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:134
static void printAngleBracketedEntries(AsmPrinter &os, T &&entries)
Pretty-print entries, each in key = value format, separated by commas.
Definition: DLTI.cpp:121
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:523
static std::string keyToStr(DataLayoutEntryKey key)
Convert pointer-union keys to strings.
Definition: DLTI.cpp:111
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:270
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:87
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:294
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:38
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:72
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:257
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:267
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:40
ParseResult value() const
Access the internal ParseResult value.
Definition: OpDefinition.h:53
bool has_value() const
Returns true if we contain a valid ParseResult value.
Definition: OpDefinition.h:50
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:167
bool operator==(const KeyTy &other) const
Definition: DLTI.cpp:176
std::pair< DataLayoutEntryKey, Attribute > KeyTy
Definition: DLTI.cpp:165
static DataLayoutEntryAttrStorage * construct(AttributeStorageAllocator &allocator, const KeyTy &key)
Definition: DLTI.cpp:171
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:537
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:21
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