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
9#include "mlir/Dialect/DLTI/DLTI.h"
10#include "mlir/IR/Builders.h"
11#include "mlir/IR/BuiltinAttributes.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"
16#include "mlir/IR/DialectImplementation.h"
17
18#include "llvm/ADT/MapVector.h"
19#include "llvm/ADT/TypeSwitch.h"
20
21using 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
38static 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(result&: type);
46 if (parsedType.has_value()) {
47 if (failed(Result: parsedType.value()))
48 return parser.emitError(loc: parser.getCurrentLocation())
49 << "error while parsing type DLTI key";
50
51 if (failed(Result: parser.parseEqual()) || failed(Result: parser.parseAttribute(result&: value)))
52 return failure();
53
54 entry = DataLayoutEntryAttr::get(key: type, value);
55 return ParseResult::success();
56 }
57 }
58
59 std::string ident;
60 OptionalParseResult parsedStr = parser.parseOptionalString(string: &ident);
61 if (parsedStr.has_value() && succeeded(Result: parsedStr.value())) {
62 if (failed(Result: parser.parseEqual()) || failed(Result: parser.parseAttribute(result&: value)))
63 return failure(); // Assume that an error has already been emitted.
64
65 entry = DataLayoutEntryAttr::get(
66 key: StringAttr::get(context: parser.getContext(), bytes: ident), value);
67 return ParseResult::success();
68 }
69
70 OptionalParseResult parsedEntry = parser.parseAttribute(result&: entry);
71 if (parsedEntry.has_value()) {
72 if (succeeded(Result: parsedEntry.value()))
73 return parsedEntry.value();
74 return failure(); // Assume that an error has already been emitted.
75 }
76 return parser.emitError(loc: 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
86template <class Attr>
87static Attribute parseAngleBracketedEntries(AsmParser &parser, Type ty,
88 bool tryType = false,
89 bool allowEmpty = false) {
90 SmallVector<DataLayoutEntryInterface> entries;
91 if (failed(parser.parseCommaSeparatedList(
92 AsmParser::Delimiter::LessGreater, [&]() {
93 return parseKeyValuePair(parser, entry&: entries.emplace_back(), tryType);
94 })))
95 return {};
96
97 if (entries.empty() && !allowEmpty) {
98 parser.emitError(loc: parser.getNameLoc()) << "no DLTI entries provided";
99 return {};
100 }
101
102 return Attr::getChecked([&] { return parser.emitError(loc: parser.getNameLoc()); },
103 parser.getContext(), ArrayRef(entries));
104}
105
106//===----------------------------------------------------------------------===//
107// Common printing utility functions.
108//===----------------------------------------------------------------------===//
109
110/// Convert pointer-union keys to strings.
111static std::string keyToStr(DataLayoutEntryKey key) {
112 std::string buf;
113 TypeSwitch<DataLayoutEntryKey>(key)
114 .Case<StringAttr, Type>( // The only two kinds of key we know of.
115 caseFn: [&](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.
120template <class T>
121static 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.
134static LogicalResult verifyEntries(function_ref<InFlightDiagnostic()> emitError,
135 ArrayRef<DataLayoutEntryInterface> entries,
136 bool allowTypes = true) {
137 DenseSet<DataLayoutEntryKey> keys;
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>(Val&: key))
145 return emitError() << "type as DLTI key is not allowed";
146 if (auto strKey = dyn_cast<StringAttr>(Val&: key))
147 if (strKey.getValue().empty())
148 return emitError() << "empty string as DLTI key is not allowed";
149 if (!keys.insert(V: 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//===----------------------------------------------------------------------===//
161namespace mlir {
162namespace detail {
163class DataLayoutEntryAttrStorage : public AttributeStorage {
164public:
165 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
166
167 DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
168 : entryKey(entryKey), value(value) {}
169
170 static DataLayoutEntryAttrStorage *
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
180 DataLayoutEntryKey entryKey;
181 Attribute value;
182};
183} // namespace detail
184} // namespace mlir
185
186DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) {
187 return Base::get(ctx: key.getContext(), args&: key, args&: value);
188}
189
190DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) {
191 return Base::get(ctx: key.getContext(), args&: key, args&: value);
192}
193
194DataLayoutEntryKey DataLayoutEntryAttr::getKey() const {
195 return getImpl()->entryKey;
196}
197
198Attribute 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 `>`
203Attribute DataLayoutEntryAttr::parse(AsmParser &parser, Type type) {
204 if (failed(Result: parser.parseLess()))
205 return {};
206
207 Type typeKey = nullptr;
208 std::string identifier;
209 SMLoc idLoc = parser.getCurrentLocation();
210 OptionalParseResult parsedType = parser.parseOptionalType(result&: typeKey);
211 if (parsedType.has_value() && failed(Result: parsedType.value()))
212 return {};
213 if (!parsedType.has_value()) {
214 OptionalParseResult parsedString = parser.parseOptionalString(string: &identifier);
215 if (!parsedString.has_value() || failed(Result: parsedString.value())) {
216 parser.emitError(loc: idLoc) << "expected a type or a quoted string";
217 return {};
218 }
219 }
220
221 Attribute value;
222 if (failed(Result: parser.parseComma()) || failed(Result: parser.parseAttribute(result&: value)) ||
223 failed(Result: parser.parseGreater()))
224 return {};
225
226 return typeKey ? get(key: typeKey, value)
227 : get(key: parser.getBuilder().getStringAttr(bytes: identifier), value);
228}
229
230void DataLayoutEntryAttr::print(AsmPrinter &printer) const {
231 printer << "<" << keyToStr(key: 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
242Attribute MapAttr::parse(AsmParser &parser, Type type) {
243 return parseAngleBracketedEntries<MapAttr>(parser, ty: type, /*tryType=*/true,
244 /*allowEmpty=*/true);
245}
246
247void MapAttr::print(AsmPrinter &printer) const {
248 printAngleBracketedEntries(os&: printer, entries: getEntries());
249}
250
251LogicalResult MapAttr::verify(function_ref<InFlightDiagnostic()> emitError,
252 ArrayRef<DataLayoutEntryInterface> entries) {
253 return verifyEntries(emitError, entries);
254}
255
256//===----------------------------------------------------------------------===//
257// DataLayoutSpecAttr
258//===----------------------------------------------------------------------===//
259
260LogicalResult
261DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
262 ArrayRef<DataLayoutEntryInterface> entries) {
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.
269static void
270overwriteDuplicateEntries(SmallVectorImpl<DataLayoutEntryInterface> &oldEntries,
271 ArrayRef<DataLayoutEntryInterface> newEntries) {
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(Elt: 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.
294static 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(types&: newEntriesForType, ids&: 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>(Val: kvp.second.getKey());
310 Dialect *dialect = id.getReferencedDialect();
311 if (!entriesForID.count(Key: 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>(Val: dialect)->combine(
321 outer: entriesForID[id], inner: kvp.second)
322 : DataLayoutDialectInterface::defaultCombine(outer: entriesForID[id],
323 inner: 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(Key: kvp.first)) {
331 entriesForType[kvp.first] = std::move(kvp.second);
332 continue;
333 }
334
335 Type typeSample = cast<Type>(Val: 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>(Val&: typeSample);
341 // TODO: Revisit this method and call once
342 // https://github.com/llvm/llvm-project/issues/130321 gets resolved.
343 if (!interface.areCompatible(oldLayout: entriesForType.lookup(Key: kvp.first), newLayout: kvp.second,
344 newSpec: spec, identified: entriesForID))
345 return failure();
346
347 overwriteDuplicateEntries(oldEntries&: entriesForType[kvp.first], newEntries: kvp.second);
348 }
349
350 return success();
351}
352
353DataLayoutSpecAttr
354DataLayoutSpecAttr::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(Range&: specs, P: [](DataLayoutSpecInterface spec) {
358 return !llvm::isa<DataLayoutSpecAttr>(Val: 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(Result: combineOneSpec(spec, entriesForType, entriesForID)))
367 return nullptr;
368 if (failed(Result: combineOneSpec(spec: *this, entriesForType, entriesForID)))
369 return nullptr;
370
371 // Rebuild the linear list of entries.
372 SmallVector<DataLayoutEntryInterface> entries;
373 llvm::append_range(C&: entries, R: llvm::make_second_range(c&: entriesForID));
374 for (const auto &kvp : entriesForType)
375 llvm::append_range(C&: entries, R: kvp.second);
376
377 return DataLayoutSpecAttr::get(context: getContext(), entries);
378}
379
380StringAttr
381DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
382 return Builder(context).getStringAttr(bytes: DLTIDialect::kDataLayoutEndiannessKey);
383}
384
385StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
386 MLIRContext *context) const {
387 return Builder(context).getStringAttr(
388 bytes: DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
389}
390
391StringAttr
392DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
393 return Builder(context).getStringAttr(
394 bytes: DLTIDialect::kDataLayoutAllocaMemorySpaceKey);
395}
396
397StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier(
398 MLIRContext *context) const {
399 return Builder(context).getStringAttr(
400 bytes: DLTIDialect::kDataLayoutProgramMemorySpaceKey);
401}
402
403StringAttr
404DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const {
405 return Builder(context).getStringAttr(
406 bytes: DLTIDialect::kDataLayoutGlobalMemorySpaceKey);
407}
408
409StringAttr
410DataLayoutSpecAttr::getManglingModeIdentifier(MLIRContext *context) const {
411 return Builder(context).getStringAttr(
412 bytes: DLTIDialect::kDataLayoutManglingModeKey);
413}
414
415StringAttr
416DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
417 return Builder(context).getStringAttr(
418 bytes: DLTIDialect::kDataLayoutStackAlignmentKey);
419}
420
421StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
422 MLIRContext *context) const {
423 return Builder(context).getStringAttr(
424 bytes: DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
425}
426
427StringAttr
428DataLayoutSpecAttr::getLegalIntWidthsIdentifier(MLIRContext *context) const {
429 return Builder(context).getStringAttr(
430 bytes: 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
437Attribute DataLayoutSpecAttr::parse(AsmParser &parser, Type type) {
438 return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, ty: type,
439 /*tryType=*/true,
440 /*allowEmpty=*/true);
441}
442
443void DataLayoutSpecAttr::print(AsmPrinter &printer) const {
444 printAngleBracketedEntries(os&: printer, entries: getEntries());
445}
446
447//===----------------------------------------------------------------------===//
448// TargetDeviceSpecAttr
449//===----------------------------------------------------------------------===//
450
451LogicalResult
452TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
453 ArrayRef<DataLayoutEntryInterface> entries) {
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
461Attribute TargetDeviceSpecAttr::parse(AsmParser &parser, Type type) {
462 return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, ty: type);
463}
464
465void TargetDeviceSpecAttr::print(AsmPrinter &printer) const {
466 printAngleBracketedEntries(os&: printer, entries: getEntries());
467}
468
469//===----------------------------------------------------------------------===//
470// TargetSystemSpecAttr
471//===----------------------------------------------------------------------===//
472
473LogicalResult
474TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
475 ArrayRef<DataLayoutEntryInterface> entries) {
476 DenseSet<TargetSystemSpecInterface::DeviceID> deviceIds;
477
478 for (const auto &entry : entries) {
479 auto deviceId =
480 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(Val: 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>(Val: entry.getValue())) {
486 if (failed(Result: TargetDeviceSpecAttr::verify(emitError,
487 entries: 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(V: 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
507Attribute TargetSystemSpecAttr::parse(AsmParser &parser, Type type) {
508 return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, ty: type);
509}
510
511void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
512 printAngleBracketedEntries(os&: printer, entries: 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.
522static std::pair<DLTIQueryInterface, Operation *>
523getClosestQueryable(Operation *op) {
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>(Val: attr.getValue())))
530 break;
531 } while (!queryable && (op = op->getParentOp()));
532
533 return std::pair(queryable, op);
534}
535
536FailureOr<Attribute>
537dlti::query(Operation *op, ArrayRef<DataLayoutEntryKey> keys, bool emitError) {
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(noteLoc: 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(noteLoc: 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(First&: keys)) {
563 if (auto map = dyn_cast<DLTIQueryInterface>(Val&: currentAttr)) {
564 auto maybeAttr = map.query(key);
565 if (failed(Result: maybeAttr)) {
566 if (emitError) {
567 auto diag = op->emitError() << "target op of failed DLTI query";
568 diag.attachNote(noteLoc: 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 c: keys.take_front(N: idx), // All prior keys.
580 each_fn: [&](auto key) { commaSeparatedKeys += keyToStr(key); },
581 between_fn: [&]() { commaSeparatedKeys += ","; });
582
583 auto diag = op->emitError() << "target op of failed DLTI query";
584 diag.attachNote(noteLoc: 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
595FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
596 bool emitError) {
597 if (!op)
598 return failure();
599
600 MLIRContext *ctx = op->getContext();
601 SmallVector<DataLayoutEntryKey> entryKeys;
602 entryKeys.reserve(N: keys.size());
603 for (StringRef key : keys)
604 entryKeys.push_back(Elt: StringAttr::get(context: ctx, bytes: key));
605
606 return dlti::query(op, keys: entryKeys, emitError);
607}
608
609constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
610constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
611constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
612constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
613
614namespace {
615class TargetDataLayoutInterface : public DataLayoutDialectInterface {
616public:
617 using DataLayoutDialectInterface::DataLayoutDialectInterface;
618
619 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
620 Location loc) const final {
621 StringRef entryName = cast<StringAttr>(Val: entry.getKey()).strref();
622 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
623 auto value = dyn_cast<StringAttr>(Val: 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
647void DLTIDialect::initialize() {
648 addAttributes<
649#define GET_ATTRDEF_LIST
650#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
651 >();
652 addInterfaces<TargetDataLayoutInterface>();
653}
654
655LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
656 NamedAttribute attr) {
657 if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
658 if (!llvm::isa<DataLayoutSpecAttr>(Val: attr.getValue())) {
659 return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
660 << "' is expected to be a #dlti.dl_spec attribute";
661 }
662 if (isa<ModuleOp>(Val: op))
663 return detail::verifyDataLayoutOp(op);
664 return success();
665 }
666
667 if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
668 if (!llvm::isa<TargetSystemSpecAttr>(Val: 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>(Val: 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}
687

source code of mlir/lib/Dialect/DLTI/DLTI.cpp