brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.4 KiB · 2ba6106 Raw
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