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"
16
17#include "llvm/ADT/MapVector.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/TypeSwitch.h"
20
21using namespace mlir;
22
23#include "mlir/Dialect/DLTI/DLTIOpInterfaces.cpp.inc"
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
40static ParseResult parseKeyValuePair(AsmParser &parser,
41 DataLayoutEntryInterface &entry,
42 bool tryType = false) {
43 Attribute value;
44
45 if (tryType) {
46 Type type;
47 OptionalParseResult parsedType = parser.parseOptionalType(type);
48 if (parsedType.has_value()) {
49 if (failed(parsedType.value()))
50 return parser.emitError(parser.getCurrentLocation())
51 << "error while parsing type DLTI key";
52
53 if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
54 return failure();
55
56 entry = DataLayoutEntryAttr::get(type, value);
57 return ParseResult::success();
58 }
59 }
60
61 std::string ident;
62 OptionalParseResult parsedStr = parser.parseOptionalString(&ident);
63 if (parsedStr.has_value() && succeeded(parsedStr.value())) {
64 if (failed(parser.parseEqual()) || failed(parser.parseAttribute(value)))
65 return failure(); // Assume that an error has already been emitted.
66
67 entry = DataLayoutEntryAttr::get(
68 StringAttr::get(parser.getContext(), ident), value);
69 return ParseResult::success();
70 }
71
72 OptionalParseResult parsedEntry = parser.parseAttribute(entry);
73 if (parsedEntry.has_value()) {
74 if (succeeded(parsedEntry.value()))
75 return parsedEntry.value();
76 return failure(); // Assume that an error has already been emitted.
77 }
78 return parser.emitError(parser.getCurrentLocation())
79 << "failed to parse DLTI entry";
80}
81
82/// Construct a requested attribute by parsing list of entries occurring within
83/// a pair of `<` and `>`, optionally allow types as keys and an empty list.
84/// The grammar is as follows:
85/// bracketed-entry-list ::=`<` entry-list `>`
86/// entry-list ::= | entry | entry `,` entry-list
87/// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
88template <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.
113static 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.
122template <class T>
123static 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//===----------------------------------------------------------------------===//
163namespace mlir {
164namespace detail {
166public:
167 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
168
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
188DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
189 return Base::get(key.getContext(), key, value);
190}
191
192DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) {
193 return Base::get(key.getContext(), key, value);
194}
195
196DataLayoutEntryKey DataLayoutEntryAttr::getKey() const {
197 return getImpl()->entryKey;
198}
199
200Attribute 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 `>`
205Attribute DataLayoutEntryAttr::parse(AsmParser &parser, Type type) {
206 if (failed(parser.parseLess()))
207 return {};
208
209 Type typeKey = nullptr;
210 std::string identifier;
211 SMLoc idLoc = parser.getCurrentLocation();
212 OptionalParseResult parsedType = parser.parseOptionalType(typeKey);
213 if (parsedType.has_value() && failed(parsedType.value()))
214 return {};
215 if (!parsedType.has_value()) {
216 OptionalParseResult parsedString = parser.parseOptionalString(&identifier);
217 if (!parsedString.has_value() || failed(parsedString.value())) {
218 parser.emitError(idLoc) << "expected a type or a quoted string";
219 return {};
220 }
221 }
222
223 Attribute value;
224 if (failed(parser.parseComma()) || failed(parser.parseAttribute(value)) ||
225 failed(parser.parseGreater()))
226 return {};
227
228 return typeKey ? get(typeKey, value)
229 : get(parser.getBuilder().getStringAttr(identifier), value);
230}
231
232void 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
244Attribute MapAttr::parse(AsmParser &parser, Type type) {
245 return parseAngleBracketedEntries<MapAttr>(parser, type, /*tryType=*/true,
246 /*allowEmpty=*/true);
247}
248
249void MapAttr::print(AsmPrinter &printer) const {
250 printAngleBracketedEntries(printer, getEntries());
251}
252
253LogicalResult MapAttr::verify(function_ref<InFlightDiagnostic()> emitError,
255 return verifyEntries(emitError, entries);
256}
257
258//===----------------------------------------------------------------------===//
259// DataLayoutSpecAttr
260//===----------------------------------------------------------------------===//
261
262LogicalResult
263DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
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.
271static 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.
296static LogicalResult combineOneSpec(
297 DataLayoutSpecInterface spec,
300 // A missing spec should be fine.
301 if (!spec)
302 return success();
303
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)
324 : DataLayoutDialectInterface::defaultCombine(entriesForID[id],
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
355DataLayoutSpecAttr
356DataLayoutSpecAttr::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.
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
382StringAttr
383DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
384 return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
385}
386
387StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
388 MLIRContext *context) const {
389 return Builder(context).getStringAttr(
390 DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
391}
392
393StringAttr
394DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
395 return Builder(context).getStringAttr(
396 DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
397}
398
399StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
400 MLIRContext *context) const {
401 return Builder(context).getStringAttr(
402 DLTIDialect::kDataLayoutProgramMemorySpaceKey);
403}
404
405StringAttr
406DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
407 return Builder(context).getStringAttr(
408 DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
409}
410
411StringAttr
412DataLayoutSpecAttr::getManglingModeIdentifier(MLIRContext *context) const {
413 return Builder(context).getStringAttr(
414 DLTIDialect::kDataLayoutManglingModeKey);
415}
416
417StringAttr
418DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
419 return Builder(context).getStringAttr(
420 DLTIDialect::kDataLayoutStackAlignmentKey);
421}
422
423StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
424 MLIRContext *context) const {
425 return Builder(context).getStringAttr(
426 DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
427}
428
429StringAttr
430DataLayoutSpecAttr::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
439Attribute DataLayoutSpecAttr::parse(AsmParser &parser, Type type) {
441 /*tryType=*/true,
442 /*allowEmpty=*/true);
443}
444
445void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
446 printAngleBracketedEntries(printer, getEntries());
447}
448
449//===----------------------------------------------------------------------===//
450// TargetDeviceSpecAttr
451//===----------------------------------------------------------------------===//
452
453LogicalResult
454TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
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
463Attribute TargetDeviceSpecAttr::parse(AsmParser &parser, Type type) {
465}
466
467void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
468 printAngleBracketedEntries(printer, getEntries());
469}
470
471//===----------------------------------------------------------------------===//
472// TargetSystemSpecAttr
473//===----------------------------------------------------------------------===//
474
475LogicalResult
476TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
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())) {
488 if (failed(TargetDeviceSpecAttr::verify(emitError,
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
509Attribute TargetSystemSpecAttr::parse(AsmParser &parser, Type type) {
511}
512
513void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
514 printAngleBracketedEntries(printer, getEntries());
515}
516
517//===----------------------------------------------------------------------===//
518// DLTIDialect
519//===----------------------------------------------------------------------===//
520
521static constexpr llvm::StringLiteral kDltiAttrName = "dlti";
522
524 DataLayoutEntryKey key) {
525 auto queryable = op->getInherentAttrOfType<DLTIQueryInterface>(kDltiAttrName);
526 if (!queryable)
527 return failure();
528 return queryable.query(key);
529}
530
532 Attribute value) {
533 if (key.isNull())
534 return failure();
535 if (auto stringKey = dyn_cast<StringAttr>(key);
536 stringKey && stringKey.getValue().empty())
537 return failure();
538
539 std::optional<Attribute> inherent = op->getInherentAttr(kDltiAttrName);
540 if (!inherent)
541 return failure();
542 auto current = dyn_cast_or_null<DLTIQueryInterface>(*inherent);
543 if (current && !isa<MapAttr>(current))
544 return failure();
545
547 if (auto map = dyn_cast_or_null<MapAttr>(current))
548 llvm::append_range(entries, map.getEntries());
549
550 auto makeEntry = [&]() -> DataLayoutEntryInterface {
551 if (auto type = dyn_cast<Type>(key))
552 return DataLayoutEntryAttr::get(type, value);
553 return DataLayoutEntryAttr::get(cast<StringAttr>(key), value);
554 };
555 auto entry = llvm::find_if(entries, [&](DataLayoutEntryInterface entry) {
556 return entry.getKey() == key;
557 });
558 if (entry != entries.end()) {
559 if (value)
560 *entry = makeEntry();
561 else
562 entries.erase(entry);
563 } else if (value) {
564 entries.push_back(makeEntry());
565 } else {
566 return success();
567 }
568
569 StringAttr attrName = StringAttr::get(op->getContext(), kDltiAttrName);
570 if (entries.empty()) {
571 op->setInherentAttr(attrName, {});
572 return success();
573 }
574 op->setInherentAttr(attrName, MapAttr::get(op->getContext(), entries));
575 return success();
576}
577
578FailureOr<Attribute>
580 if (!op)
581 return failure();
582
583 if (keys.empty()) {
584 if (emitError) {
585 auto diag = op->emitError() << "target op of failed DLTI query";
586 diag.attachNote(op->getLoc()) << "no keys provided to attempt query with";
587 }
588 return failure();
589 }
590
591 Attribute currentAttr;
592 Operation *queryOp = op;
593 for (; queryOp; queryOp = queryOp->getParentOp()) {
594 auto queryable = dyn_cast<DLTIQueryOpInterface>(queryOp);
595 if (!queryable)
596 continue;
597 FailureOr<Attribute> result = queryable.queryDlti(keys.front());
598 if (succeeded(result)) {
599 currentAttr = *result;
600 break;
601 }
602 }
603
604 if (!currentAttr) {
605 if (emitError) {
606 auto diag = op->emitError() << "target op of failed DLTI query";
607 diag.attachNote(op->getLoc())
608 << "no DLTI-queryable operation on the target or any of its "
609 "ancestors could answer key "
610 << keyToStr(keys.front());
611 }
612 return failure();
613 }
614
615 for (auto &&[idx, key] : llvm::enumerate(keys.drop_front())) {
616 if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
617 auto maybeAttr = map.query(key);
618 if (failed(maybeAttr)) {
619 if (emitError) {
620 auto diag = op->emitError() << "target op of failed DLTI query";
621 diag.attachNote(queryOp->getLoc())
622 << "key " << keyToStr(key)
623 << " has no DLTI-mapping per attr: " << map;
624 }
625 return failure();
626 }
627 currentAttr = *maybeAttr;
628 } else {
629 if (emitError) {
630 std::string commaSeparatedKeys;
631 llvm::interleave(
632 keys.take_front(idx + 1), // All prior keys.
633 [&](auto key) { commaSeparatedKeys += keyToStr(key); },
634 [&]() { commaSeparatedKeys += ","; });
635
636 auto diag = op->emitError() << "target op of failed DLTI query";
637 diag.attachNote(queryOp->getLoc())
638 << "got non-DLTI-queryable attribute upon looking up keys ["
639 << commaSeparatedKeys << "] at op";
640 }
641 return failure();
642 }
643 }
644
645 return currentAttr;
646}
647
648FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
649 bool emitError) {
650 if (!op)
651 return failure();
652
653 MLIRContext *ctx = op->getContext();
655 entryKeys.reserve(keys.size());
656 for (StringRef key : keys)
657 entryKeys.push_back(StringAttr::get(ctx, key));
658
659 return dlti::query(op, entryKeys, emitError);
660}
661
662namespace {
663struct ModuleDLTIQueryOpInterface
664 : DLTIQueryOpInterface::ExternalModel<ModuleDLTIQueryOpInterface,
665 ModuleOp> {};
666
667class TargetDataLayoutInterface : public DataLayoutDialectInterface {
668public:
669 using DataLayoutDialectInterface::DataLayoutDialectInterface;
670
671 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
672 Location loc) const final {
673 StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
674 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
675 auto value = dyn_cast<StringAttr>(entry.getValue());
676 if (value &&
677 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
678 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
679 return success();
680 return emitError(loc) << "'" << entryName
681 << "' data layout entry is expected to be either '"
682 << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
683 << DLTIDialect::kDataLayoutEndiannessLittle << "'";
684 }
685 if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
686 entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
687 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
688 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
689 entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
690 entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
691 entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
692 entryName == DLTIDialect::kDataLayoutManglingModeKey)
693 return success();
694 return emitError(loc) << "unknown data layout entry name: " << entryName;
695 }
696};
697} // namespace
698
699void DLTIDialect::initialize() {
700 addAttributes<
701#define GET_ATTRDEF_LIST
702#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
703 >();
704 addInterfaces<TargetDataLayoutInterface>();
705 ModuleOp::attachInterface<ModuleDLTIQueryOpInterface>(*getContext());
706}
707
708LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
709 NamedAttribute attr) {
710 if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
711 if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
712 return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
713 << "' is expected to be a #dlti.dl_spec attribute";
714 }
715 if (isa<ModuleOp>(op))
717 return success();
718 }
719
720 if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
721 if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
722 return op->emitError()
723 << "'" << DLTIDialect::kTargetSystemDescAttrName
724 << "' is expected to be a #dlti.target_system_spec attribute";
725 }
726 return success();
727 }
728
729 if (attr.getName() == DLTIDialect::kMapAttrName) {
730 if (!llvm::isa<MapAttr>(attr.getValue())) {
731 return op->emitError() << "'" << DLTIDialect::kMapAttrName
732 << "' is expected to be a #dlti.map attribute";
733 }
734 return success();
735 }
736
737 return op->emitError() << "attribute '" << attr.getName().getValue()
738 << "' not supported by dialect";
739}
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:136
static void printAngleBracketedEntries(AsmPrinter &os, T &&entries)
Pretty-print entries, each in key = value format, separated by commas.
Definition DLTI.cpp:123
static constexpr llvm::StringLiteral kDltiAttrName
Definition DLTI.cpp:521
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
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:71
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:166
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
Definition Attributes.h:181
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:474
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:173
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
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:531
FailureOr< Attribute > queryDlti(Operation *op, DataLayoutEntryKey key)
Definition DLTI.cpp:523
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:579
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
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