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