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#include "llvm/Support/Debug.h"
21#include "llvm/Support/MathExtras.h"
22
23using namespace mlir;
24
25#include "mlir/Dialect/DLTI/DLTIDialect.cpp.inc"
26
27#define GET_ATTRDEF_CLASSES
28#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
29
30#define DEBUG_TYPE "dlti"
31
32//===----------------------------------------------------------------------===//
33// Common parsing utility functions.
34//===----------------------------------------------------------------------===//
35
36/// Parse an entry which can either be of the form `key = value` or a
37/// #dlti.dl_entry attribute. When `tryType=true` the key can be a type,
38/// otherwise only quoted strings are allowed. The grammar is as follows:
39/// entry ::= ((type | quoted-string) `=` attr) | dl-entry-attr
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(result&: type);
48 if (parsedType.has_value()) {
49 if (failed(Result: parsedType.value()))
50 return parser.emitError(loc: parser.getCurrentLocation())
51 << "error while parsing type DLTI key";
52
53 if (failed(Result: parser.parseEqual()) || failed(Result: parser.parseAttribute(result&: 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(string: &ident);
63 if (parsedStr.has_value() && succeeded(Result: parsedStr.value())) {
64 if (failed(Result: parser.parseEqual()) || failed(Result: parser.parseAttribute(result&: 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(result&: entry);
73 if (parsedEntry.has_value()) {
74 if (succeeded(Result: parsedEntry.value()))
75 return parsedEntry.value();
76 return failure(); // Assume that an error has already been emitted.
77 }
78 return parser.emitError(loc: 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>
89static Attribute parseAngleBracketedEntries(AsmParser &parser, Type ty,
90 bool tryType = false,
91 bool allowEmpty = false) {
92 SmallVector<DataLayoutEntryInterface> entries;
93 if (failed(parser.parseCommaSeparatedList(
94 AsmParser::Delimiter::LessGreater, [&]() {
95 return parseKeyValuePair(parser, entries.emplace_back(), tryType);
96 })))
97 return {};
98
99 if (entries.empty() && !allowEmpty) {
100 parser.emitError(loc: parser.getNameLoc()) << "no DLTI entries provided";
101 return {};
102 }
103
104 return Attr::getChecked([&] { return parser.emitError(loc: 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;
115 TypeSwitch<DataLayoutEntryKey>(key)
116 .Case<StringAttr, Type>( // The only two kinds of key we know of.
117 caseFn: [&](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.
136static LogicalResult verifyEntries(function_ref<InFlightDiagnostic()> emitError,
137 ArrayRef<DataLayoutEntryInterface> entries,
138 bool allowTypes = true) {
139 DenseSet<DataLayoutEntryKey> keys;
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 {
165class DataLayoutEntryAttrStorage : public AttributeStorage {
166public:
167 using KeyTy = std::pair<DataLayoutEntryKey, Attribute>;
168
169 DataLayoutEntryAttrStorage(DataLayoutEntryKey entryKey, Attribute value)
170 : entryKey(entryKey), value(value) {}
171
172 static DataLayoutEntryAttrStorage *
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
182 DataLayoutEntryKey entryKey;
183 Attribute value;
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,
254 ArrayRef<DataLayoutEntryInterface> entries) {
255 return verifyEntries(emitError, entries);
256}
257
258//===----------------------------------------------------------------------===//
259// DataLayoutSpecAttr
260//===----------------------------------------------------------------------===//
261
262LogicalResult
263DataLayoutSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError,
264 ArrayRef<DataLayoutEntryInterface> entries) {
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
272overwriteDuplicateEntries(SmallVectorImpl<DataLayoutEntryInterface> &oldEntries,
273 ArrayRef<DataLayoutEntryInterface> newEntries) {
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,
298 llvm::MapVector<TypeID, DataLayoutEntryList> &entriesForType,
299 llvm::MapVector<StringAttr, DataLayoutEntryInterface> &entriesForID) {
300 // A missing spec should be fine.
301 if (!spec)
302 return success();
303
304 llvm::MapVector<TypeID, DataLayoutEntryList> newEntriesForType;
305 llvm::MapVector<StringAttr, DataLayoutEntryInterface> newEntriesForID;
306 spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
307
308 // Combine non-Type DL entries first so they are visible to the
309 // `type.areCompatible` method, allowing to query global properties.
310 for (const auto &kvp : newEntriesForID) {
311 StringAttr id = cast<StringAttr>(kvp.second.getKey());
312 Dialect *dialect = id.getReferencedDialect();
313 if (!entriesForID.count(Key: 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>(Val: dialect)->combine(
323 outer: entriesForID[id], inner: kvp.second)
324 : DataLayoutDialectInterface::defaultCombine(outer: entriesForID[id],
325 inner: 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(Key: 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(Key: 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.
365 llvm::MapVector<TypeID, DataLayoutEntryList> entriesForType;
366 llvm::MapVector<StringAttr, DataLayoutEntryInterface> entriesForID;
367 for (DataLayoutSpecInterface spec : specs)
368 if (failed(combineOneSpec(spec, entriesForType, entriesForID)))
369 return nullptr;
370 if (failed(combineOneSpec(*this, entriesForType, entriesForID)))
371 return nullptr;
372
373 // Rebuild the linear list of entries.
374 SmallVector<DataLayoutEntryInterface> 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) {
440 return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, 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,
455 ArrayRef<DataLayoutEntryInterface> entries) {
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) {
464 return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, 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,
477 ArrayRef<DataLayoutEntryInterface> entries) {
478 DenseSet<TargetSystemSpecInterface::DeviceID> deviceIds;
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) {
510 return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type);
511}
512
513void TargetSystemSpecAttr::print(AsmPrinter &printer) const {
514 printAngleBracketedEntries(printer, getEntries());
515}
516
517//===----------------------------------------------------------------------===//
518// DLTIDialect
519//===----------------------------------------------------------------------===//
520
521/// Retrieve the first `DLTIQueryInterface`-implementing attribute that is
522/// attached to `op` or such an attr on as close as possible an ancestor. The
523/// op the attribute is attached to is returned as well.
524static std::pair<DLTIQueryInterface, Operation *>
525getClosestQueryable(Operation *op) {
526 DLTIQueryInterface queryable = {};
527
528 // Search op and its ancestors for the first attached DLTIQueryInterface attr.
529 do {
530 for (NamedAttribute attr : op->getAttrs())
531 if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue())))
532 break;
533 } while (!queryable && (op = op->getParentOp()));
534
535 return std::pair(queryable, op);
536}
537
538FailureOr<Attribute>
539dlti::query(Operation *op, ArrayRef<DataLayoutEntryKey> keys, bool emitError) {
540 if (!op)
541 return failure();
542
543 if (keys.empty()) {
544 if (emitError) {
545 auto diag = op->emitError() << "target op of failed DLTI query";
546 diag.attachNote(noteLoc: op->getLoc()) << "no keys provided to attempt query with";
547 }
548 return failure();
549 }
550
551 auto [queryable, queryOp] = getClosestQueryable(op);
552 Operation *reportOp = (queryOp ? queryOp : op);
553
554 if (!queryable) {
555 if (emitError) {
556 auto diag = op->emitError() << "target op of failed DLTI query";
557 diag.attachNote(noteLoc: reportOp->getLoc())
558 << "no DLTI-queryable attrs on target op or any of its ancestors";
559 }
560 return failure();
561 }
562
563 Attribute currentAttr = queryable;
564 for (auto &&[idx, key] : llvm::enumerate(First&: keys)) {
565 if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) {
566 auto maybeAttr = map.query(key);
567 if (failed(maybeAttr)) {
568 if (emitError) {
569 auto diag = op->emitError() << "target op of failed DLTI query";
570 diag.attachNote(noteLoc: reportOp->getLoc())
571 << "key " << keyToStr(key)
572 << " has no DLTI-mapping per attr: " << map;
573 }
574 return failure();
575 }
576 currentAttr = *maybeAttr;
577 } else {
578 if (emitError) {
579 std::string commaSeparatedKeys;
580 llvm::interleave(
581 c: keys.take_front(N: idx), // All prior keys.
582 each_fn: [&](auto key) { commaSeparatedKeys += keyToStr(key); },
583 between_fn: [&]() { commaSeparatedKeys += ","; });
584
585 auto diag = op->emitError() << "target op of failed DLTI query";
586 diag.attachNote(noteLoc: reportOp->getLoc())
587 << "got non-DLTI-queryable attribute upon looking up keys ["
588 << commaSeparatedKeys << "] at op";
589 }
590 return failure();
591 }
592 }
593
594 return currentAttr;
595}
596
597FailureOr<Attribute> dlti::query(Operation *op, ArrayRef<StringRef> keys,
598 bool emitError) {
599 if (!op)
600 return failure();
601
602 MLIRContext *ctx = op->getContext();
603 SmallVector<DataLayoutEntryKey> entryKeys;
604 entryKeys.reserve(N: keys.size());
605 for (StringRef key : keys)
606 entryKeys.push_back(StringAttr::get(ctx, key));
607
608 return dlti::query(op, keys: entryKeys, emitError);
609}
610
611constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName;
612constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey;
613constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig;
614constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle;
615
616namespace {
617class TargetDataLayoutInterface : public DataLayoutDialectInterface {
618public:
619 using DataLayoutDialectInterface::DataLayoutDialectInterface;
620
621 LogicalResult verifyEntry(DataLayoutEntryInterface entry,
622 Location loc) const final {
623 StringRef entryName = cast<StringAttr>(entry.getKey()).strref();
624 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) {
625 auto value = dyn_cast<StringAttr>(entry.getValue());
626 if (value &&
627 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig ||
628 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle))
629 return success();
630 return emitError(loc) << "'" << entryName
631 << "' data layout entry is expected to be either '"
632 << DLTIDialect::kDataLayoutEndiannessBig << "' or '"
633 << DLTIDialect::kDataLayoutEndiannessLittle << "'";
634 }
635 if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
636 entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
637 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
638 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
639 entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
640 entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
641 entryName == DLTIDialect::kDataLayoutLegalIntWidthsKey ||
642 entryName == DLTIDialect::kDataLayoutManglingModeKey)
643 return success();
644 return emitError(loc) << "unknown data layout entry name: " << entryName;
645 }
646};
647} // namespace
648
649void DLTIDialect::initialize() {
650 addAttributes<
651#define GET_ATTRDEF_LIST
652#include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc"
653 >();
654 addInterfaces<TargetDataLayoutInterface>();
655}
656
657LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op,
658 NamedAttribute attr) {
659 if (attr.getName() == DLTIDialect::kDataLayoutAttrName) {
660 if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) {
661 return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName
662 << "' is expected to be a #dlti.dl_spec attribute";
663 }
664 if (isa<ModuleOp>(op))
665 return detail::verifyDataLayoutOp(op);
666 return success();
667 }
668
669 if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) {
670 if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) {
671 return op->emitError()
672 << "'" << DLTIDialect::kTargetSystemDescAttrName
673 << "' is expected to be a #dlti.target_system_spec attribute";
674 }
675 return success();
676 }
677
678 if (attr.getName() == DLTIDialect::kMapAttrName) {
679 if (!llvm::isa<MapAttr>(attr.getValue())) {
680 return op->emitError() << "'" << DLTIDialect::kMapAttrName
681 << "' is expected to be a #dlti.map attribute";
682 }
683 return success();
684 }
685
686 return op->emitError() << "attribute '" << attr.getName().getValue()
687 << "' not supported by dialect";
688}
689

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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