692 lines · cpp
1//===- SPIRVAttributes.cpp - SPIR-V attribute definitions -----------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"10#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"11#include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"12#include "mlir/IR/Builders.h"13#include "mlir/IR/DialectImplementation.h"14#include "llvm/ADT/TypeSwitch.h"15#include "llvm/Support/InterleavedRange.h"16 17using namespace mlir;18using namespace mlir::spirv;19 20//===----------------------------------------------------------------------===//21// TableGen'erated attribute utility functions22//===----------------------------------------------------------------------===//23 24namespace mlir {25namespace spirv {26#include "mlir/Dialect/SPIRV/IR/SPIRVAttrUtils.inc"27} // namespace spirv28 29//===----------------------------------------------------------------------===//30// Attribute storage classes31//===----------------------------------------------------------------------===//32 33namespace spirv {34namespace detail {35 36struct InterfaceVarABIAttributeStorage : public AttributeStorage {37 using KeyTy = std::tuple<Attribute, Attribute, Attribute>;38 39 InterfaceVarABIAttributeStorage(Attribute descriptorSet, Attribute binding,40 Attribute storageClass)41 : descriptorSet(descriptorSet), binding(binding),42 storageClass(storageClass) {}43 44 bool operator==(const KeyTy &key) const {45 return std::get<0>(key) == descriptorSet && std::get<1>(key) == binding &&46 std::get<2>(key) == storageClass;47 }48 49 static InterfaceVarABIAttributeStorage *50 construct(AttributeStorageAllocator &allocator, const KeyTy &key) {51 return new (allocator.allocate<InterfaceVarABIAttributeStorage>())52 InterfaceVarABIAttributeStorage(std::get<0>(key), std::get<1>(key),53 std::get<2>(key));54 }55 56 Attribute descriptorSet;57 Attribute binding;58 Attribute storageClass;59};60 61struct VerCapExtAttributeStorage : public AttributeStorage {62 using KeyTy = std::tuple<Attribute, Attribute, Attribute>;63 64 VerCapExtAttributeStorage(Attribute version, Attribute capabilities,65 Attribute extensions)66 : version(version), capabilities(capabilities), extensions(extensions) {}67 68 bool operator==(const KeyTy &key) const {69 return std::get<0>(key) == version && std::get<1>(key) == capabilities &&70 std::get<2>(key) == extensions;71 }72 73 static VerCapExtAttributeStorage *74 construct(AttributeStorageAllocator &allocator, const KeyTy &key) {75 return new (allocator.allocate<VerCapExtAttributeStorage>())76 VerCapExtAttributeStorage(std::get<0>(key), std::get<1>(key),77 std::get<2>(key));78 }79 80 Attribute version;81 Attribute capabilities;82 Attribute extensions;83};84 85struct TargetEnvAttributeStorage : public AttributeStorage {86 using KeyTy =87 std::tuple<Attribute, ClientAPI, Vendor, DeviceType, uint32_t, Attribute>;88 89 TargetEnvAttributeStorage(Attribute triple, ClientAPI clientAPI,90 Vendor vendorID, DeviceType deviceType,91 uint32_t deviceID, Attribute limits)92 : triple(triple), limits(limits), clientAPI(clientAPI),93 vendorID(vendorID), deviceType(deviceType), deviceID(deviceID) {}94 95 bool operator==(const KeyTy &key) const {96 return key == std::make_tuple(triple, clientAPI, vendorID, deviceType,97 deviceID, limits);98 }99 100 static TargetEnvAttributeStorage *101 construct(AttributeStorageAllocator &allocator, const KeyTy &key) {102 return new (allocator.allocate<TargetEnvAttributeStorage>())103 TargetEnvAttributeStorage(std::get<0>(key), std::get<1>(key),104 std::get<2>(key), std::get<3>(key),105 std::get<4>(key), std::get<5>(key));106 }107 108 Attribute triple;109 Attribute limits;110 ClientAPI clientAPI;111 Vendor vendorID;112 DeviceType deviceType;113 uint32_t deviceID;114};115} // namespace detail116} // namespace spirv117} // namespace mlir118 119//===----------------------------------------------------------------------===//120// InterfaceVarABIAttr121//===----------------------------------------------------------------------===//122 123spirv::InterfaceVarABIAttr124spirv::InterfaceVarABIAttr::get(uint32_t descriptorSet, uint32_t binding,125 std::optional<spirv::StorageClass> storageClass,126 MLIRContext *context) {127 Builder b(context);128 auto descriptorSetAttr = b.getI32IntegerAttr(descriptorSet);129 auto bindingAttr = b.getI32IntegerAttr(binding);130 auto storageClassAttr =131 storageClass ? b.getI32IntegerAttr(static_cast<uint32_t>(*storageClass))132 : IntegerAttr();133 return get(descriptorSetAttr, bindingAttr, storageClassAttr);134}135 136spirv::InterfaceVarABIAttr137spirv::InterfaceVarABIAttr::get(IntegerAttr descriptorSet, IntegerAttr binding,138 IntegerAttr storageClass) {139 assert(descriptorSet && binding);140 MLIRContext *context = descriptorSet.getContext();141 return Base::get(context, descriptorSet, binding, storageClass);142}143 144StringRef spirv::InterfaceVarABIAttr::getKindName() {145 return "interface_var_abi";146}147 148uint32_t spirv::InterfaceVarABIAttr::getBinding() {149 return llvm::cast<IntegerAttr>(getImpl()->binding).getInt();150}151 152uint32_t spirv::InterfaceVarABIAttr::getDescriptorSet() {153 return llvm::cast<IntegerAttr>(getImpl()->descriptorSet).getInt();154}155 156std::optional<spirv::StorageClass>157spirv::InterfaceVarABIAttr::getStorageClass() {158 if (getImpl()->storageClass)159 return static_cast<spirv::StorageClass>(160 llvm::cast<IntegerAttr>(getImpl()->storageClass)161 .getValue()162 .getZExtValue());163 return std::nullopt;164}165 166LogicalResult spirv::InterfaceVarABIAttr::verifyInvariants(167 function_ref<InFlightDiagnostic()> emitError, IntegerAttr descriptorSet,168 IntegerAttr binding, IntegerAttr storageClass) {169 if (!descriptorSet.getType().isSignlessInteger(32))170 return emitError() << "expected 32-bit integer for descriptor set";171 172 if (!binding.getType().isSignlessInteger(32))173 return emitError() << "expected 32-bit integer for binding";174 175 if (storageClass) {176 if (auto storageClassAttr = llvm::cast<IntegerAttr>(storageClass)) {177 auto storageClassValue =178 spirv::symbolizeStorageClass(storageClassAttr.getInt());179 if (!storageClassValue)180 return emitError() << "unknown storage class";181 } else {182 return emitError() << "expected valid storage class";183 }184 }185 186 return success();187}188 189//===----------------------------------------------------------------------===//190// VerCapExtAttr191//===----------------------------------------------------------------------===//192 193spirv::VerCapExtAttr spirv::VerCapExtAttr::get(194 spirv::Version version, ArrayRef<spirv::Capability> capabilities,195 ArrayRef<spirv::Extension> extensions, MLIRContext *context) {196 Builder b(context);197 198 auto versionAttr = b.getI32IntegerAttr(static_cast<uint32_t>(version));199 200 SmallVector<Attribute, 4> capAttrs;201 capAttrs.reserve(capabilities.size());202 for (spirv::Capability cap : capabilities)203 capAttrs.push_back(b.getI32IntegerAttr(static_cast<uint32_t>(cap)));204 205 SmallVector<Attribute, 4> extAttrs;206 extAttrs.reserve(extensions.size());207 for (spirv::Extension ext : extensions)208 extAttrs.push_back(b.getStringAttr(spirv::stringifyExtension(ext)));209 210 return get(versionAttr, b.getArrayAttr(capAttrs), b.getArrayAttr(extAttrs));211}212 213spirv::VerCapExtAttr spirv::VerCapExtAttr::get(IntegerAttr version,214 ArrayAttr capabilities,215 ArrayAttr extensions) {216 assert(version && capabilities && extensions);217 MLIRContext *context = version.getContext();218 return Base::get(context, version, capabilities, extensions);219}220 221StringRef spirv::VerCapExtAttr::getKindName() { return "vce"; }222 223spirv::Version spirv::VerCapExtAttr::getVersion() {224 return static_cast<spirv::Version>(225 llvm::cast<IntegerAttr>(getImpl()->version).getValue().getZExtValue());226}227 228spirv::VerCapExtAttr::ext_iterator::ext_iterator(ArrayAttr::iterator it)229 : llvm::mapped_iterator<ArrayAttr::iterator,230 spirv::Extension (*)(Attribute)>(231 it, [](Attribute attr) {232 return *symbolizeExtension(llvm::cast<StringAttr>(attr).getValue());233 }) {}234 235spirv::VerCapExtAttr::ext_range spirv::VerCapExtAttr::getExtensions() {236 auto range = getExtensionsAttr().getValue();237 return {ext_iterator(range.begin()), ext_iterator(range.end())};238}239 240ArrayAttr spirv::VerCapExtAttr::getExtensionsAttr() {241 return llvm::cast<ArrayAttr>(getImpl()->extensions);242}243 244spirv::VerCapExtAttr::cap_iterator::cap_iterator(ArrayAttr::iterator it)245 : llvm::mapped_iterator<ArrayAttr::iterator,246 spirv::Capability (*)(Attribute)>(247 it, [](Attribute attr) {248 return *symbolizeCapability(249 llvm::cast<IntegerAttr>(attr).getValue().getZExtValue());250 }) {}251 252spirv::VerCapExtAttr::cap_range spirv::VerCapExtAttr::getCapabilities() {253 auto range = getCapabilitiesAttr().getValue();254 return {cap_iterator(range.begin()), cap_iterator(range.end())};255}256 257ArrayAttr spirv::VerCapExtAttr::getCapabilitiesAttr() {258 return llvm::cast<ArrayAttr>(getImpl()->capabilities);259}260 261LogicalResult spirv::VerCapExtAttr::verifyInvariants(262 function_ref<InFlightDiagnostic()> emitError, IntegerAttr version,263 ArrayAttr capabilities, ArrayAttr extensions) {264 if (!version.getType().isSignlessInteger(32))265 return emitError() << "expected 32-bit integer for version";266 267 if (!llvm::all_of(capabilities.getValue(), [](Attribute attr) {268 if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr))269 if (spirv::symbolizeCapability(intAttr.getValue().getZExtValue()))270 return true;271 return false;272 }))273 return emitError() << "unknown capability in capability list";274 275 if (!llvm::all_of(extensions.getValue(), [](Attribute attr) {276 if (auto strAttr = llvm::dyn_cast<StringAttr>(attr))277 if (spirv::symbolizeExtension(strAttr.getValue()))278 return true;279 return false;280 }))281 return emitError() << "unknown extension in extension list";282 283 return success();284}285 286//===----------------------------------------------------------------------===//287// TargetEnvAttr288//===----------------------------------------------------------------------===//289 290spirv::TargetEnvAttr spirv::TargetEnvAttr::get(291 spirv::VerCapExtAttr triple, ResourceLimitsAttr limits, ClientAPI clientAPI,292 Vendor vendorID, DeviceType deviceType, uint32_t deviceID) {293 assert(triple && limits && "expected valid triple and limits");294 MLIRContext *context = triple.getContext();295 return Base::get(context, triple, clientAPI, vendorID, deviceType, deviceID,296 limits);297}298 299StringRef spirv::TargetEnvAttr::getKindName() { return "target_env"; }300 301spirv::VerCapExtAttr spirv::TargetEnvAttr::getTripleAttr() const {302 return llvm::cast<spirv::VerCapExtAttr>(getImpl()->triple);303}304 305spirv::Version spirv::TargetEnvAttr::getVersion() const {306 return getTripleAttr().getVersion();307}308 309spirv::VerCapExtAttr::ext_range spirv::TargetEnvAttr::getExtensions() {310 return getTripleAttr().getExtensions();311}312 313ArrayAttr spirv::TargetEnvAttr::getExtensionsAttr() {314 return getTripleAttr().getExtensionsAttr();315}316 317spirv::VerCapExtAttr::cap_range spirv::TargetEnvAttr::getCapabilities() {318 return getTripleAttr().getCapabilities();319}320 321ArrayAttr spirv::TargetEnvAttr::getCapabilitiesAttr() {322 return getTripleAttr().getCapabilitiesAttr();323}324 325spirv::ClientAPI spirv::TargetEnvAttr::getClientAPI() const {326 return getImpl()->clientAPI;327}328 329spirv::Vendor spirv::TargetEnvAttr::getVendorID() const {330 return getImpl()->vendorID;331}332 333spirv::DeviceType spirv::TargetEnvAttr::getDeviceType() const {334 return getImpl()->deviceType;335}336 337uint32_t spirv::TargetEnvAttr::getDeviceID() const {338 return getImpl()->deviceID;339}340 341spirv::ResourceLimitsAttr spirv::TargetEnvAttr::getResourceLimits() const {342 return llvm::cast<spirv::ResourceLimitsAttr>(getImpl()->limits);343}344 345//===----------------------------------------------------------------------===//346// ODS Generated Attributes347//===----------------------------------------------------------------------===//348 349#define GET_ATTRDEF_CLASSES350#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.cpp.inc"351 352//===----------------------------------------------------------------------===//353// Attribute Parsing354//===----------------------------------------------------------------------===//355 356/// Parses a comma-separated list of keywords, invokes `processKeyword` on each357/// of the parsed keyword, and returns failure if any error occurs.358static ParseResult359parseKeywordList(DialectAsmParser &parser,360 function_ref<LogicalResult(SMLoc, StringRef)> processKeyword) {361 if (parser.parseLSquare())362 return failure();363 364 // Special case for empty list.365 if (succeeded(parser.parseOptionalRSquare()))366 return success();367 368 // Keep parsing the keyword and an optional comma following it. If the comma369 // is successfully parsed, then we have more keywords to parse.370 if (failed(parser.parseCommaSeparatedList([&]() {371 auto loc = parser.getCurrentLocation();372 StringRef keyword;373 if (parser.parseKeyword(&keyword) ||374 failed(processKeyword(loc, keyword)))375 return failure();376 return success();377 })))378 return failure();379 return parser.parseRSquare();380}381 382/// Parses a spirv::InterfaceVarABIAttr.383static Attribute parseInterfaceVarABIAttr(DialectAsmParser &parser) {384 if (parser.parseLess())385 return {};386 387 Builder &builder = parser.getBuilder();388 389 if (parser.parseLParen())390 return {};391 392 IntegerAttr descriptorSetAttr;393 {394 auto loc = parser.getCurrentLocation();395 uint32_t descriptorSet = 0;396 auto descriptorSetParseResult = parser.parseOptionalInteger(descriptorSet);397 398 if (!descriptorSetParseResult.has_value() ||399 failed(*descriptorSetParseResult)) {400 parser.emitError(loc, "missing descriptor set");401 return {};402 }403 descriptorSetAttr = builder.getI32IntegerAttr(descriptorSet);404 }405 406 if (parser.parseComma())407 return {};408 409 IntegerAttr bindingAttr;410 {411 auto loc = parser.getCurrentLocation();412 uint32_t binding = 0;413 auto bindingParseResult = parser.parseOptionalInteger(binding);414 415 if (!bindingParseResult.has_value() || failed(*bindingParseResult)) {416 parser.emitError(loc, "missing binding");417 return {};418 }419 bindingAttr = builder.getI32IntegerAttr(binding);420 }421 422 if (parser.parseRParen())423 return {};424 425 IntegerAttr storageClassAttr;426 {427 if (succeeded(parser.parseOptionalComma())) {428 auto loc = parser.getCurrentLocation();429 StringRef storageClass;430 if (parser.parseKeyword(&storageClass))431 return {};432 433 if (auto storageClassSymbol =434 spirv::symbolizeStorageClass(storageClass)) {435 storageClassAttr = builder.getI32IntegerAttr(436 static_cast<uint32_t>(*storageClassSymbol));437 } else {438 parser.emitError(loc, "unknown storage class: ") << storageClass;439 return {};440 }441 }442 }443 444 if (parser.parseGreater())445 return {};446 447 return spirv::InterfaceVarABIAttr::get(descriptorSetAttr, bindingAttr,448 storageClassAttr);449}450 451static Attribute parseVerCapExtAttr(DialectAsmParser &parser) {452 if (parser.parseLess())453 return {};454 455 Builder &builder = parser.getBuilder();456 457 IntegerAttr versionAttr;458 {459 auto loc = parser.getCurrentLocation();460 StringRef version;461 if (parser.parseKeyword(&version) || parser.parseComma())462 return {};463 464 if (auto versionSymbol = spirv::symbolizeVersion(version)) {465 versionAttr =466 builder.getI32IntegerAttr(static_cast<uint32_t>(*versionSymbol));467 } else {468 parser.emitError(loc, "unknown version: ") << version;469 return {};470 }471 }472 473 ArrayAttr capabilitiesAttr;474 {475 SmallVector<Attribute, 4> capabilities;476 SMLoc errorloc;477 StringRef errorKeyword;478 479 auto processCapability = [&](SMLoc loc, StringRef capability) {480 if (auto capSymbol = spirv::symbolizeCapability(capability)) {481 capabilities.push_back(482 builder.getI32IntegerAttr(static_cast<uint32_t>(*capSymbol)));483 return success();484 }485 return errorloc = loc, errorKeyword = capability, failure();486 };487 if (parseKeywordList(parser, processCapability) || parser.parseComma()) {488 if (!errorKeyword.empty())489 parser.emitError(errorloc, "unknown capability: ") << errorKeyword;490 return {};491 }492 493 capabilitiesAttr = builder.getArrayAttr(capabilities);494 }495 496 ArrayAttr extensionsAttr;497 {498 SmallVector<Attribute, 1> extensions;499 SMLoc errorloc;500 StringRef errorKeyword;501 502 auto processExtension = [&](SMLoc loc, StringRef extension) {503 if (spirv::symbolizeExtension(extension)) {504 extensions.push_back(builder.getStringAttr(extension));505 return success();506 }507 return errorloc = loc, errorKeyword = extension, failure();508 };509 if (parseKeywordList(parser, processExtension)) {510 if (!errorKeyword.empty())511 parser.emitError(errorloc, "unknown extension: ") << errorKeyword;512 return {};513 }514 515 extensionsAttr = builder.getArrayAttr(extensions);516 }517 518 if (parser.parseGreater())519 return {};520 521 return spirv::VerCapExtAttr::get(versionAttr, capabilitiesAttr,522 extensionsAttr);523}524 525/// Parses a spirv::TargetEnvAttr.526static Attribute parseTargetEnvAttr(DialectAsmParser &parser) {527 if (parser.parseLess())528 return {};529 530 spirv::VerCapExtAttr tripleAttr;531 if (parser.parseAttribute(tripleAttr) || parser.parseComma())532 return {};533 534 auto clientAPI = spirv::ClientAPI::Unknown;535 if (succeeded(parser.parseOptionalKeyword("api"))) {536 if (parser.parseEqual())537 return {};538 auto loc = parser.getCurrentLocation();539 StringRef apiStr;540 if (parser.parseKeyword(&apiStr))541 return {};542 if (auto apiSymbol = spirv::symbolizeClientAPI(apiStr))543 clientAPI = *apiSymbol;544 else545 parser.emitError(loc, "unknown client API: ") << apiStr;546 if (parser.parseComma())547 return {};548 }549 550 // Parse [vendor[:device-type[:device-id]]]551 Vendor vendorID = Vendor::Unknown;552 DeviceType deviceType = DeviceType::Unknown;553 uint32_t deviceID = spirv::TargetEnvAttr::kUnknownDeviceID;554 {555 auto loc = parser.getCurrentLocation();556 StringRef vendorStr;557 if (succeeded(parser.parseOptionalKeyword(&vendorStr))) {558 if (auto vendorSymbol = spirv::symbolizeVendor(vendorStr))559 vendorID = *vendorSymbol;560 else561 parser.emitError(loc, "unknown vendor: ") << vendorStr;562 563 if (succeeded(parser.parseOptionalColon())) {564 loc = parser.getCurrentLocation();565 StringRef deviceTypeStr;566 if (parser.parseKeyword(&deviceTypeStr))567 return {};568 if (auto deviceTypeSymbol = spirv::symbolizeDeviceType(deviceTypeStr))569 deviceType = *deviceTypeSymbol;570 else571 parser.emitError(loc, "unknown device type: ") << deviceTypeStr;572 573 if (succeeded(parser.parseOptionalColon())) {574 loc = parser.getCurrentLocation();575 if (parser.parseInteger(deviceID))576 return {};577 }578 }579 if (parser.parseComma())580 return {};581 }582 }583 584 ResourceLimitsAttr limitsAttr;585 if (parser.parseAttribute(limitsAttr) || parser.parseGreater())586 return {};587 588 return spirv::TargetEnvAttr::get(tripleAttr, limitsAttr, clientAPI, vendorID,589 deviceType, deviceID);590}591 592Attribute SPIRVDialect::parseAttribute(DialectAsmParser &parser,593 Type type) const {594 // SPIR-V attributes are dictionaries so they do not have type.595 if (type) {596 parser.emitError(parser.getNameLoc(), "unexpected type");597 return {};598 }599 600 // Parse the kind keyword first.601 StringRef attrKind;602 Attribute attr;603 OptionalParseResult result =604 generatedAttributeParser(parser, &attrKind, type, attr);605 if (result.has_value())606 return attr;607 608 if (attrKind == spirv::TargetEnvAttr::getKindName())609 return parseTargetEnvAttr(parser);610 if (attrKind == spirv::VerCapExtAttr::getKindName())611 return parseVerCapExtAttr(parser);612 if (attrKind == spirv::InterfaceVarABIAttr::getKindName())613 return parseInterfaceVarABIAttr(parser);614 615 parser.emitError(parser.getNameLoc(), "unknown SPIR-V attribute kind: ")616 << attrKind;617 return {};618}619 620//===----------------------------------------------------------------------===//621// Attribute Printing622//===----------------------------------------------------------------------===//623 624static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer) {625 printer << spirv::VerCapExtAttr::getKindName() << "<"626 << spirv::stringifyVersion(triple.getVersion()) << ", "627 << llvm::interleaved_array(llvm::map_range(628 triple.getCapabilities(), spirv::stringifyCapability))629 << ", "630 << llvm::interleaved_array(631 triple.getExtensionsAttr().getAsValueRange<StringAttr>())632 << ">";633}634 635static void print(spirv::TargetEnvAttr targetEnv, DialectAsmPrinter &printer) {636 printer << spirv::TargetEnvAttr::getKindName() << "<#spirv.";637 print(targetEnv.getTripleAttr(), printer);638 auto clientAPI = targetEnv.getClientAPI();639 if (clientAPI != spirv::ClientAPI::Unknown)640 printer << ", api=" << clientAPI;641 spirv::Vendor vendorID = targetEnv.getVendorID();642 spirv::DeviceType deviceType = targetEnv.getDeviceType();643 uint32_t deviceID = targetEnv.getDeviceID();644 if (vendorID != spirv::Vendor::Unknown) {645 printer << ", " << spirv::stringifyVendor(vendorID);646 if (deviceType != spirv::DeviceType::Unknown) {647 printer << ":" << spirv::stringifyDeviceType(deviceType);648 if (deviceID != spirv::TargetEnvAttr::kUnknownDeviceID)649 printer << ":" << deviceID;650 }651 }652 printer << ", " << targetEnv.getResourceLimits() << ">";653}654 655static void print(spirv::InterfaceVarABIAttr interfaceVarABIAttr,656 DialectAsmPrinter &printer) {657 printer << spirv::InterfaceVarABIAttr::getKindName() << "<("658 << interfaceVarABIAttr.getDescriptorSet() << ", "659 << interfaceVarABIAttr.getBinding() << ")";660 auto storageClass = interfaceVarABIAttr.getStorageClass();661 if (storageClass)662 printer << ", " << spirv::stringifyStorageClass(*storageClass);663 printer << ">";664}665 666void SPIRVDialect::printAttribute(Attribute attr,667 DialectAsmPrinter &printer) const {668 if (succeeded(generatedAttributePrinter(attr, printer)))669 return;670 671 if (auto targetEnv = llvm::dyn_cast<TargetEnvAttr>(attr))672 print(targetEnv, printer);673 else if (auto vceAttr = llvm::dyn_cast<VerCapExtAttr>(attr))674 print(vceAttr, printer);675 else if (auto interfaceVarABIAttr = llvm::dyn_cast<InterfaceVarABIAttr>(attr))676 print(interfaceVarABIAttr, printer);677 else678 llvm_unreachable("unhandled SPIR-V attribute kind");679}680 681//===----------------------------------------------------------------------===//682// SPIR-V Dialect683//===----------------------------------------------------------------------===//684 685void spirv::SPIRVDialect::registerAttributes() {686 addAttributes<InterfaceVarABIAttr, TargetEnvAttr, VerCapExtAttr>();687 addAttributes<688#define GET_ATTRDEF_LIST689#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.cpp.inc"690 >();691}692