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 #include "llvm/ADT/TypeSwitch.h" 18 19 #include "llvm/ADT/TypeSwitch.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/MathExtras.h" 22 23 using 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 40 static 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 88 template <class Attr> 89 static 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(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. 113 static 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 [&](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. 122 template <class T> 123 static 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. 136 static 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 //===----------------------------------------------------------------------===// 163 namespace mlir { 164 namespace detail { 165 class DataLayoutEntryAttrStorage : public AttributeStorage { 166 public: 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 188 DataLayoutEntryAttr DataLayoutEntryAttr::get(StringAttr key, Attribute value) { 189 return Base::get(key.getContext(), key, value); 190 } 191 192 DataLayoutEntryAttr DataLayoutEntryAttr::get(Type key, Attribute value) { 193 return Base::get(key.getContext(), key, value); 194 } 195 196 DataLayoutEntryKey DataLayoutEntryAttr::getKey() const { 197 return getImpl()->entryKey; 198 } 199 200 Attribute 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 `>` 205 Attribute 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 232 void 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 244 Attribute MapAttr::parse(AsmParser &parser, Type type) { 245 return parseAngleBracketedEntries<MapAttr>(parser, type, /*tryType=*/true, 246 /*allowEmpty=*/true); 247 } 248 249 void MapAttr::print(AsmPrinter &printer) const { 250 printAngleBracketedEntries(printer, getEntries()); 251 } 252 253 LogicalResult MapAttr::verify(function_ref<InFlightDiagnostic()> emitError, 254 ArrayRef<DataLayoutEntryInterface> entries) { 255 return verifyEntries(emitError, entries); 256 } 257 258 //===----------------------------------------------------------------------===// 259 // DataLayoutSpecAttr 260 //===----------------------------------------------------------------------===// 261 262 LogicalResult 263 DataLayoutSpecAttr::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. 271 static void 272 overwriteDuplicateEntries(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. 296 static LogicalResult 297 combineOneSpec(DataLayoutSpecInterface spec, 298 DenseMap<TypeID, DataLayoutEntryList> &entriesForType, 299 DenseMap<StringAttr, DataLayoutEntryInterface> &entriesForID) { 300 // A missing spec should be fine. 301 if (!spec) 302 return success(); 303 304 DenseMap<TypeID, DataLayoutEntryList> newEntriesForType; 305 DenseMap<StringAttr, DataLayoutEntryInterface> newEntriesForID; 306 spec.bucketEntriesByType(newEntriesForType, newEntriesForID); 307 308 // Try overwriting the old entries with the new ones. 309 for (auto &kvp : newEntriesForType) { 310 if (!entriesForType.count(kvp.first)) { 311 entriesForType[kvp.first] = std::move(kvp.second); 312 continue; 313 } 314 315 Type typeSample = cast<Type>(kvp.second.front().getKey()); 316 assert(&typeSample.getDialect() != 317 typeSample.getContext()->getLoadedDialect<BuiltinDialect>() && 318 "unexpected data layout entry for built-in type"); 319 320 auto interface = cast<DataLayoutTypeInterface>(typeSample); 321 if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second)) 322 return failure(); 323 324 overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second); 325 } 326 327 for (const auto &kvp : newEntriesForID) { 328 StringAttr id = cast<StringAttr>(kvp.second.getKey()); 329 Dialect *dialect = id.getReferencedDialect(); 330 if (!entriesForID.count(id)) { 331 entriesForID[id] = kvp.second; 332 continue; 333 } 334 335 // Attempt to combine the enties using the dialect interface. If the 336 // dialect is not loaded for some reason, use the default combinator 337 // that conservatively accepts identical entries only. 338 entriesForID[id] = 339 dialect ? cast<DataLayoutDialectInterface>(dialect)->combine( 340 entriesForID[id], kvp.second) 341 : DataLayoutDialectInterface::defaultCombine(entriesForID[id], 342 kvp.second); 343 if (!entriesForID[id]) 344 return failure(); 345 } 346 347 return success(); 348 } 349 350 DataLayoutSpecAttr 351 DataLayoutSpecAttr::combineWith(ArrayRef<DataLayoutSpecInterface> specs) const { 352 // Only combine with attributes of the same kind. 353 // TODO: reconsider this when the need arises. 354 if (any_of(specs, [](DataLayoutSpecInterface spec) { 355 return !llvm::isa<DataLayoutSpecAttr>(spec); 356 })) 357 return {}; 358 359 // Combine all specs in order, with `this` being the last one. 360 DenseMap<TypeID, DataLayoutEntryList> entriesForType; 361 DenseMap<StringAttr, DataLayoutEntryInterface> entriesForID; 362 for (DataLayoutSpecInterface spec : specs) 363 if (failed(combineOneSpec(spec, entriesForType, entriesForID))) 364 return nullptr; 365 if (failed(combineOneSpec(*this, entriesForType, entriesForID))) 366 return nullptr; 367 368 // Rebuild the linear list of entries. 369 SmallVector<DataLayoutEntryInterface> entries; 370 llvm::append_range(entries, llvm::make_second_range(entriesForID)); 371 for (const auto &kvp : entriesForType) 372 llvm::append_range(entries, kvp.getSecond()); 373 374 return DataLayoutSpecAttr::get(getContext(), entries); 375 } 376 377 StringAttr 378 DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const { 379 return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey); 380 } 381 382 StringAttr 383 DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const { 384 return Builder(context).getStringAttr( 385 DLTIDialect::kDataLayoutAllocaMemorySpaceKey); 386 } 387 388 StringAttr DataLayoutSpecAttr::getProgramMemorySpaceIdentifier( 389 MLIRContext *context) const { 390 return Builder(context).getStringAttr( 391 DLTIDialect::kDataLayoutProgramMemorySpaceKey); 392 } 393 394 StringAttr 395 DataLayoutSpecAttr::getGlobalMemorySpaceIdentifier(MLIRContext *context) const { 396 return Builder(context).getStringAttr( 397 DLTIDialect::kDataLayoutGlobalMemorySpaceKey); 398 } 399 400 StringAttr 401 DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const { 402 return Builder(context).getStringAttr( 403 DLTIDialect::kDataLayoutStackAlignmentKey); 404 } 405 406 /// Parses an attribute with syntax: 407 /// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>` 408 /// entry-list ::= | entry | entry `,` entry-list 409 /// entry ::= ((type | quoted-string) = attr) | dl-entry-attr 410 Attribute DataLayoutSpecAttr::parse(AsmParser &parser, Type type) { 411 return parseAngleBracketedEntries<DataLayoutSpecAttr>(parser, type, 412 /*tryType=*/true, 413 /*allowEmpty=*/true); 414 } 415 416 void DataLayoutSpecAttr::print(AsmPrinter &printer) const { 417 printAngleBracketedEntries(printer, getEntries()); 418 } 419 420 //===----------------------------------------------------------------------===// 421 // TargetDeviceSpecAttr 422 //===----------------------------------------------------------------------===// 423 424 LogicalResult 425 TargetDeviceSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError, 426 ArrayRef<DataLayoutEntryInterface> entries) { 427 return verifyEntries(emitError, entries, /*allowTypes=*/false); 428 } 429 430 /// Parses an attribute with syntax: 431 /// dev-spec-attr ::= `#dlti.` `target_device_spec` `<` entry-list `>` 432 /// entry-list ::= entry | entry `,` entry-list 433 /// entry ::= (quoted-string `=` attr) | dl-entry-attr 434 Attribute TargetDeviceSpecAttr::parse(AsmParser &parser, Type type) { 435 return parseAngleBracketedEntries<TargetDeviceSpecAttr>(parser, type); 436 } 437 438 void TargetDeviceSpecAttr::print(AsmPrinter &printer) const { 439 printAngleBracketedEntries(printer, getEntries()); 440 } 441 442 //===----------------------------------------------------------------------===// 443 // TargetSystemSpecAttr 444 //===----------------------------------------------------------------------===// 445 446 LogicalResult 447 TargetSystemSpecAttr::verify(function_ref<InFlightDiagnostic()> emitError, 448 ArrayRef<DataLayoutEntryInterface> entries) { 449 DenseSet<TargetSystemSpecInterface::DeviceID> deviceIds; 450 451 for (const auto &entry : entries) { 452 auto deviceId = 453 llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey()); 454 if (!deviceId) 455 return emitError() << "non-string key of DLTI system spec"; 456 457 if (auto targetDeviceSpec = 458 llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) { 459 if (failed(TargetDeviceSpecAttr::verify(emitError, 460 targetDeviceSpec.getEntries()))) 461 return failure(); // Assume sub-verifier outputted error message. 462 } else { 463 return emitError() << "value associated with key " << deviceId 464 << " is not a DLTI device spec"; 465 } 466 467 // Check that device IDs are unique across all entries. 468 if (!deviceIds.insert(deviceId).second) 469 return emitError() << "repeated device ID in dlti.target_system_spec: " 470 << deviceId; 471 } 472 473 return success(); 474 } 475 476 /// Parses an attribute with syntax: 477 /// sys-spec-attr ::= `#dlti.` `target_system_spec` `<` entry-list `>` 478 /// entry-list ::= entry | entry `,` entry-list 479 /// entry ::= (quoted-string `=` dev-spec-attr) | dl-entry-attr 480 Attribute TargetSystemSpecAttr::parse(AsmParser &parser, Type type) { 481 return parseAngleBracketedEntries<TargetSystemSpecAttr>(parser, type); 482 } 483 484 void TargetSystemSpecAttr::print(AsmPrinter &printer) const { 485 printAngleBracketedEntries(printer, getEntries()); 486 } 487 488 //===----------------------------------------------------------------------===// 489 // DLTIDialect 490 //===----------------------------------------------------------------------===// 491 492 /// Retrieve the first `DLTIQueryInterface`-implementing attribute that is 493 /// attached to `op` or such an attr on as close as possible an ancestor. The 494 /// op the attribute is attached to is returned as well. 495 static std::pair<DLTIQueryInterface, Operation *> 496 getClosestQueryable(Operation *op) { 497 DLTIQueryInterface queryable = {}; 498 499 // Search op and its ancestors for the first attached DLTIQueryInterface attr. 500 do { 501 for (NamedAttribute attr : op->getAttrs()) 502 if ((queryable = dyn_cast<DLTIQueryInterface>(attr.getValue()))) 503 break; 504 } while (!queryable && (op = op->getParentOp())); 505 506 return std::pair(queryable, op); 507 } 508 509 FailureOr<Attribute> 510 dlti::query(Operation *op, ArrayRef<DataLayoutEntryKey> keys, bool emitError) { 511 if (keys.empty()) { 512 if (emitError) { 513 auto diag = op->emitError() << "target op of failed DLTI query"; 514 diag.attachNote(op->getLoc()) << "no keys provided to attempt query with"; 515 } 516 return failure(); 517 } 518 519 auto [queryable, queryOp] = getClosestQueryable(op); 520 Operation *reportOp = (queryOp ? queryOp : op); 521 522 if (!queryable) { 523 if (emitError) { 524 auto diag = op->emitError() << "target op of failed DLTI query"; 525 diag.attachNote(reportOp->getLoc()) 526 << "no DLTI-queryable attrs on target op or any of its ancestors"; 527 } 528 return failure(); 529 } 530 531 Attribute currentAttr = queryable; 532 for (auto &&[idx, key] : llvm::enumerate(keys)) { 533 if (auto map = dyn_cast<DLTIQueryInterface>(currentAttr)) { 534 auto maybeAttr = map.query(key); 535 if (failed(maybeAttr)) { 536 if (emitError) { 537 auto diag = op->emitError() << "target op of failed DLTI query"; 538 diag.attachNote(reportOp->getLoc()) 539 << "key " << keyToStr(key) 540 << " has no DLTI-mapping per attr: " << map; 541 } 542 return failure(); 543 } 544 currentAttr = *maybeAttr; 545 } else { 546 if (emitError) { 547 std::string commaSeparatedKeys; 548 llvm::interleave( 549 keys.take_front(idx), // All prior keys. 550 [&](auto key) { commaSeparatedKeys += keyToStr(key); }, 551 [&]() { commaSeparatedKeys += ","; }); 552 553 auto diag = op->emitError() << "target op of failed DLTI query"; 554 diag.attachNote(reportOp->getLoc()) 555 << "got non-DLTI-queryable attribute upon looking up keys [" 556 << commaSeparatedKeys << "] at op"; 557 } 558 return failure(); 559 } 560 } 561 562 return currentAttr; 563 } 564 565 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutAttrName; 566 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessKey; 567 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessBig; 568 constexpr const StringLiteral mlir::DLTIDialect::kDataLayoutEndiannessLittle; 569 570 namespace { 571 class TargetDataLayoutInterface : public DataLayoutDialectInterface { 572 public: 573 using DataLayoutDialectInterface::DataLayoutDialectInterface; 574 575 LogicalResult verifyEntry(DataLayoutEntryInterface entry, 576 Location loc) const final { 577 StringRef entryName = cast<StringAttr>(entry.getKey()).strref(); 578 if (entryName == DLTIDialect::kDataLayoutEndiannessKey) { 579 auto value = dyn_cast<StringAttr>(entry.getValue()); 580 if (value && 581 (value.getValue() == DLTIDialect::kDataLayoutEndiannessBig || 582 value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle)) 583 return success(); 584 return emitError(loc) << "'" << entryName 585 << "' data layout entry is expected to be either '" 586 << DLTIDialect::kDataLayoutEndiannessBig << "' or '" 587 << DLTIDialect::kDataLayoutEndiannessLittle << "'"; 588 } 589 if (entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey || 590 entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey || 591 entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey || 592 entryName == DLTIDialect::kDataLayoutStackAlignmentKey) 593 return success(); 594 return emitError(loc) << "unknown data layout entry name: " << entryName; 595 } 596 }; 597 } // namespace 598 599 void DLTIDialect::initialize() { 600 addAttributes< 601 #define GET_ATTRDEF_LIST 602 #include "mlir/Dialect/DLTI/DLTIAttrs.cpp.inc" 603 >(); 604 addInterfaces<TargetDataLayoutInterface>(); 605 } 606 607 LogicalResult DLTIDialect::verifyOperationAttribute(Operation *op, 608 NamedAttribute attr) { 609 if (attr.getName() == DLTIDialect::kDataLayoutAttrName) { 610 if (!llvm::isa<DataLayoutSpecAttr>(attr.getValue())) { 611 return op->emitError() << "'" << DLTIDialect::kDataLayoutAttrName 612 << "' is expected to be a #dlti.dl_spec attribute"; 613 } 614 if (isa<ModuleOp>(op)) 615 return detail::verifyDataLayoutOp(op); 616 return success(); 617 } 618 619 if (attr.getName() == DLTIDialect::kTargetSystemDescAttrName) { 620 if (!llvm::isa<TargetSystemSpecAttr>(attr.getValue())) { 621 return op->emitError() 622 << "'" << DLTIDialect::kTargetSystemDescAttrName 623 << "' is expected to be a #dlti.target_system_spec attribute"; 624 } 625 return success(); 626 } 627 628 if (attr.getName() == DLTIDialect::kMapAttrName) { 629 if (!llvm::isa<MapAttr>(attr.getValue())) { 630 return op->emitError() << "'" << DLTIDialect::kMapAttrName 631 << "' is expected to be a #dlti.map attribute"; 632 } 633 return success(); 634 } 635 636 return op->emitError() << "attribute '" << attr.getName().getValue() 637 << "' not supported by dialect"; 638 } 639