| //===- SPIRVAttributes.cpp - SPIR-V attribute definitions -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h" |
| #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h" |
| #include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h" |
| #include "mlir/IR/Builders.h" |
| #include "mlir/IR/DialectImplementation.h" |
| #include "llvm/ADT/TypeSwitch.h" |
| #include "llvm/Support/InterleavedRange.h" |
| |
| using namespace mlir; |
| using namespace mlir::spirv; |
| |
| //===----------------------------------------------------------------------===// |
| // TableGen'erated attribute utility functions |
| //===----------------------------------------------------------------------===// |
| |
| namespace mlir { |
| namespace spirv { |
| #include "mlir/Dialect/SPIRV/IR/SPIRVAttrUtils.inc" |
| } // namespace spirv |
| |
| //===----------------------------------------------------------------------===// |
| // Attribute storage classes |
| //===----------------------------------------------------------------------===// |
| |
| namespace spirv { |
| namespace detail { |
| |
| struct InterfaceVarABIAttributeStorage : public AttributeStorage { |
| using KeyTy = std::tuple<Attribute, Attribute, Attribute>; |
| |
| InterfaceVarABIAttributeStorage(Attribute descriptorSet, Attribute binding, |
| Attribute storageClass) |
| : descriptorSet(descriptorSet), binding(binding), |
| storageClass(storageClass) {} |
| |
| bool operator==(const KeyTy &key) const { |
| return std::get<0>(key) == descriptorSet && std::get<1>(key) == binding && |
| std::get<2>(key) == storageClass; |
| } |
| |
| static InterfaceVarABIAttributeStorage * |
| construct(AttributeStorageAllocator &allocator, const KeyTy &key) { |
| return new (allocator.allocate<InterfaceVarABIAttributeStorage>()) |
| InterfaceVarABIAttributeStorage(std::get<0>(key), std::get<1>(key), |
| std::get<2>(key)); |
| } |
| |
| Attribute descriptorSet; |
| Attribute binding; |
| Attribute storageClass; |
| }; |
| |
| struct VerCapExtAttributeStorage : public AttributeStorage { |
| using KeyTy = std::tuple<Attribute, Attribute, Attribute>; |
| |
| VerCapExtAttributeStorage(Attribute version, Attribute capabilities, |
| Attribute extensions) |
| : version(version), capabilities(capabilities), extensions(extensions) {} |
| |
| bool operator==(const KeyTy &key) const { |
| return std::get<0>(key) == version && std::get<1>(key) == capabilities && |
| std::get<2>(key) == extensions; |
| } |
| |
| static VerCapExtAttributeStorage * |
| construct(AttributeStorageAllocator &allocator, const KeyTy &key) { |
| return new (allocator.allocate<VerCapExtAttributeStorage>()) |
| VerCapExtAttributeStorage(std::get<0>(key), std::get<1>(key), |
| std::get<2>(key)); |
| } |
| |
| Attribute version; |
| Attribute capabilities; |
| Attribute extensions; |
| }; |
| |
| struct TargetEnvAttributeStorage : public AttributeStorage { |
| using KeyTy = |
| std::tuple<Attribute, ClientAPI, Vendor, DeviceType, uint32_t, Attribute>; |
| |
| TargetEnvAttributeStorage(Attribute triple, ClientAPI clientAPI, |
| Vendor vendorID, DeviceType deviceType, |
| uint32_t deviceID, Attribute limits) |
| : triple(triple), limits(limits), clientAPI(clientAPI), |
| vendorID(vendorID), deviceType(deviceType), deviceID(deviceID) {} |
| |
| bool operator==(const KeyTy &key) const { |
| return key == std::make_tuple(triple, clientAPI, vendorID, deviceType, |
| deviceID, limits); |
| } |
| |
| static TargetEnvAttributeStorage * |
| construct(AttributeStorageAllocator &allocator, const KeyTy &key) { |
| return new (allocator.allocate<TargetEnvAttributeStorage>()) |
| TargetEnvAttributeStorage(std::get<0>(key), std::get<1>(key), |
| std::get<2>(key), std::get<3>(key), |
| std::get<4>(key), std::get<5>(key)); |
| } |
| |
| Attribute triple; |
| Attribute limits; |
| ClientAPI clientAPI; |
| Vendor vendorID; |
| DeviceType deviceType; |
| uint32_t deviceID; |
| }; |
| } // namespace detail |
| } // namespace spirv |
| } // namespace mlir |
| |
| //===----------------------------------------------------------------------===// |
| // InterfaceVarABIAttr |
| //===----------------------------------------------------------------------===// |
| |
| spirv::InterfaceVarABIAttr |
| spirv::InterfaceVarABIAttr::get(uint32_t descriptorSet, uint32_t binding, |
| std::optional<spirv::StorageClass> storageClass, |
| MLIRContext *context) { |
| Builder b(context); |
| auto descriptorSetAttr = b.getI32IntegerAttr(descriptorSet); |
| auto bindingAttr = b.getI32IntegerAttr(binding); |
| auto storageClassAttr = |
| storageClass ? b.getI32IntegerAttr(static_cast<uint32_t>(*storageClass)) |
| : IntegerAttr(); |
| return get(descriptorSetAttr, bindingAttr, storageClassAttr); |
| } |
| |
| spirv::InterfaceVarABIAttr |
| spirv::InterfaceVarABIAttr::get(IntegerAttr descriptorSet, IntegerAttr binding, |
| IntegerAttr storageClass) { |
| assert(descriptorSet && binding); |
| MLIRContext *context = descriptorSet.getContext(); |
| return Base::get(context, descriptorSet, binding, storageClass); |
| } |
| |
| StringRef spirv::InterfaceVarABIAttr::getKindName() { |
| return "interface_var_abi"; |
| } |
| |
| uint32_t spirv::InterfaceVarABIAttr::getBinding() { |
| return cast<IntegerAttr>(getImpl()->binding).getInt(); |
| } |
| |
| uint32_t spirv::InterfaceVarABIAttr::getDescriptorSet() { |
| return cast<IntegerAttr>(getImpl()->descriptorSet).getInt(); |
| } |
| |
| std::optional<spirv::StorageClass> |
| spirv::InterfaceVarABIAttr::getStorageClass() { |
| if (getImpl()->storageClass) |
| return static_cast<spirv::StorageClass>( |
| cast<IntegerAttr>(getImpl()->storageClass).getValue().getZExtValue()); |
| return std::nullopt; |
| } |
| |
| LogicalResult spirv::InterfaceVarABIAttr::verifyInvariants( |
| function_ref<InFlightDiagnostic()> emitError, IntegerAttr descriptorSet, |
| IntegerAttr binding, IntegerAttr storageClass) { |
| if (!descriptorSet.getType().isSignlessInteger(32)) |
| return emitError() << "expected 32-bit integer for descriptor set"; |
| |
| if (!binding.getType().isSignlessInteger(32)) |
| return emitError() << "expected 32-bit integer for binding"; |
| |
| if (storageClass) { |
| if (auto storageClassAttr = cast<IntegerAttr>(storageClass)) { |
| auto storageClassValue = |
| spirv::symbolizeStorageClass(storageClassAttr.getInt()); |
| if (!storageClassValue) |
| return emitError() << "unknown storage class"; |
| } else { |
| return emitError() << "expected valid storage class"; |
| } |
| } |
| |
| return success(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // VerCapExtAttr |
| //===----------------------------------------------------------------------===// |
| |
| spirv::VerCapExtAttr spirv::VerCapExtAttr::get( |
| spirv::Version version, ArrayRef<spirv::Capability> capabilities, |
| ArrayRef<spirv::Extension> extensions, MLIRContext *context) { |
| Builder b(context); |
| |
| auto versionAttr = b.getI32IntegerAttr(static_cast<uint32_t>(version)); |
| |
| SmallVector<Attribute, 4> capAttrs; |
| capAttrs.reserve(capabilities.size()); |
| for (spirv::Capability cap : capabilities) |
| capAttrs.push_back(b.getI32IntegerAttr(static_cast<uint32_t>(cap))); |
| |
| SmallVector<Attribute, 4> extAttrs; |
| extAttrs.reserve(extensions.size()); |
| for (spirv::Extension ext : extensions) |
| extAttrs.push_back(b.getStringAttr(spirv::stringifyExtension(ext))); |
| |
| return get(versionAttr, b.getArrayAttr(capAttrs), b.getArrayAttr(extAttrs)); |
| } |
| |
| spirv::VerCapExtAttr spirv::VerCapExtAttr::get(IntegerAttr version, |
| ArrayAttr capabilities, |
| ArrayAttr extensions) { |
| assert(version && capabilities && extensions); |
| MLIRContext *context = version.getContext(); |
| return Base::get(context, version, capabilities, extensions); |
| } |
| |
| StringRef spirv::VerCapExtAttr::getKindName() { return "vce"; } |
| |
| spirv::Version spirv::VerCapExtAttr::getVersion() { |
| return static_cast<spirv::Version>( |
| cast<IntegerAttr>(getImpl()->version).getValue().getZExtValue()); |
| } |
| |
| spirv::VerCapExtAttr::ext_iterator::ext_iterator(ArrayAttr::iterator it) |
| : llvm::mapped_iterator<ArrayAttr::iterator, |
| spirv::Extension (*)(Attribute)>( |
| it, [](Attribute attr) { |
| return *symbolizeExtension(cast<StringAttr>(attr).getValue()); |
| }) {} |
| |
| spirv::VerCapExtAttr::ext_range spirv::VerCapExtAttr::getExtensions() { |
| auto range = getExtensionsAttr().getValue(); |
| return {ext_iterator(range.begin()), ext_iterator(range.end())}; |
| } |
| |
| ArrayAttr spirv::VerCapExtAttr::getExtensionsAttr() { |
| return cast<ArrayAttr>(getImpl()->extensions); |
| } |
| |
| spirv::VerCapExtAttr::cap_iterator::cap_iterator(ArrayAttr::iterator it) |
| : llvm::mapped_iterator<ArrayAttr::iterator, |
| spirv::Capability (*)(Attribute)>( |
| it, [](Attribute attr) { |
| return *symbolizeCapability( |
| cast<IntegerAttr>(attr).getValue().getZExtValue()); |
| }) {} |
| |
| spirv::VerCapExtAttr::cap_range spirv::VerCapExtAttr::getCapabilities() { |
| auto range = getCapabilitiesAttr().getValue(); |
| return {cap_iterator(range.begin()), cap_iterator(range.end())}; |
| } |
| |
| ArrayAttr spirv::VerCapExtAttr::getCapabilitiesAttr() { |
| return cast<ArrayAttr>(getImpl()->capabilities); |
| } |
| |
| LogicalResult spirv::VerCapExtAttr::verifyInvariants( |
| function_ref<InFlightDiagnostic()> emitError, IntegerAttr version, |
| ArrayAttr capabilities, ArrayAttr extensions) { |
| if (!version.getType().isSignlessInteger(32)) |
| return emitError() << "expected 32-bit integer for version"; |
| |
| if (!llvm::all_of(capabilities.getValue(), [](Attribute attr) { |
| if (auto intAttr = dyn_cast<IntegerAttr>(attr)) |
| if (spirv::symbolizeCapability(intAttr.getValue().getZExtValue())) |
| return true; |
| return false; |
| })) |
| return emitError() << "unknown capability in capability list"; |
| |
| if (!llvm::all_of(extensions.getValue(), [](Attribute attr) { |
| if (auto strAttr = dyn_cast<StringAttr>(attr)) |
| if (spirv::symbolizeExtension(strAttr.getValue())) |
| return true; |
| return false; |
| })) |
| return emitError() << "unknown extension in extension list"; |
| |
| return success(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // TargetEnvAttr |
| //===----------------------------------------------------------------------===// |
| |
| spirv::TargetEnvAttr spirv::TargetEnvAttr::get( |
| spirv::VerCapExtAttr triple, ResourceLimitsAttr limits, ClientAPI clientAPI, |
| Vendor vendorID, DeviceType deviceType, uint32_t deviceID) { |
| assert(triple && limits && "expected valid triple and limits"); |
| MLIRContext *context = triple.getContext(); |
| return Base::get(context, triple, clientAPI, vendorID, deviceType, deviceID, |
| limits); |
| } |
| |
| StringRef spirv::TargetEnvAttr::getKindName() { return "target_env"; } |
| |
| spirv::VerCapExtAttr spirv::TargetEnvAttr::getTripleAttr() const { |
| return cast<spirv::VerCapExtAttr>(getImpl()->triple); |
| } |
| |
| spirv::Version spirv::TargetEnvAttr::getVersion() const { |
| return getTripleAttr().getVersion(); |
| } |
| |
| spirv::VerCapExtAttr::ext_range spirv::TargetEnvAttr::getExtensions() { |
| return getTripleAttr().getExtensions(); |
| } |
| |
| ArrayAttr spirv::TargetEnvAttr::getExtensionsAttr() { |
| return getTripleAttr().getExtensionsAttr(); |
| } |
| |
| spirv::VerCapExtAttr::cap_range spirv::TargetEnvAttr::getCapabilities() { |
| return getTripleAttr().getCapabilities(); |
| } |
| |
| ArrayAttr spirv::TargetEnvAttr::getCapabilitiesAttr() { |
| return getTripleAttr().getCapabilitiesAttr(); |
| } |
| |
| spirv::ClientAPI spirv::TargetEnvAttr::getClientAPI() const { |
| return getImpl()->clientAPI; |
| } |
| |
| spirv::Vendor spirv::TargetEnvAttr::getVendorID() const { |
| return getImpl()->vendorID; |
| } |
| |
| spirv::DeviceType spirv::TargetEnvAttr::getDeviceType() const { |
| return getImpl()->deviceType; |
| } |
| |
| uint32_t spirv::TargetEnvAttr::getDeviceID() const { |
| return getImpl()->deviceID; |
| } |
| |
| spirv::ResourceLimitsAttr spirv::TargetEnvAttr::getResourceLimits() const { |
| return cast<spirv::ResourceLimitsAttr>(getImpl()->limits); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // ODS Generated Attributes |
| //===----------------------------------------------------------------------===// |
| |
| #define GET_ATTRDEF_CLASSES |
| #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.cpp.inc" |
| |
| //===----------------------------------------------------------------------===// |
| // Attribute Parsing |
| //===----------------------------------------------------------------------===// |
| |
| /// Parses a comma-separated list of keywords, invokes `processKeyword` on each |
| /// of the parsed keyword, and returns failure if any error occurs. |
| static ParseResult |
| parseKeywordList(DialectAsmParser &parser, |
| function_ref<LogicalResult(SMLoc, StringRef)> processKeyword) { |
| if (parser.parseLSquare()) |
| return failure(); |
| |
| // Special case for empty list. |
| if (succeeded(parser.parseOptionalRSquare())) |
| return success(); |
| |
| // Keep parsing the keyword and an optional comma following it. If the comma |
| // is successfully parsed, then we have more keywords to parse. |
| if (failed(parser.parseCommaSeparatedList([&]() { |
| auto loc = parser.getCurrentLocation(); |
| StringRef keyword; |
| if (parser.parseKeyword(&keyword) || |
| failed(processKeyword(loc, keyword))) |
| return failure(); |
| return success(); |
| }))) |
| return failure(); |
| return parser.parseRSquare(); |
| } |
| |
| /// Parses a spirv::InterfaceVarABIAttr. |
| static Attribute parseInterfaceVarABIAttr(DialectAsmParser &parser) { |
| if (parser.parseLess()) |
| return {}; |
| |
| Builder &builder = parser.getBuilder(); |
| |
| if (parser.parseLParen()) |
| return {}; |
| |
| IntegerAttr descriptorSetAttr; |
| { |
| auto loc = parser.getCurrentLocation(); |
| uint32_t descriptorSet = 0; |
| auto descriptorSetParseResult = parser.parseOptionalInteger(descriptorSet); |
| |
| if (!descriptorSetParseResult.has_value() || |
| failed(*descriptorSetParseResult)) { |
| parser.emitError(loc, "missing descriptor set"); |
| return {}; |
| } |
| descriptorSetAttr = builder.getI32IntegerAttr(descriptorSet); |
| } |
| |
| if (parser.parseComma()) |
| return {}; |
| |
| IntegerAttr bindingAttr; |
| { |
| auto loc = parser.getCurrentLocation(); |
| uint32_t binding = 0; |
| auto bindingParseResult = parser.parseOptionalInteger(binding); |
| |
| if (!bindingParseResult.has_value() || failed(*bindingParseResult)) { |
| parser.emitError(loc, "missing binding"); |
| return {}; |
| } |
| bindingAttr = builder.getI32IntegerAttr(binding); |
| } |
| |
| if (parser.parseRParen()) |
| return {}; |
| |
| IntegerAttr storageClassAttr; |
| { |
| if (succeeded(parser.parseOptionalComma())) { |
| auto loc = parser.getCurrentLocation(); |
| StringRef storageClass; |
| if (parser.parseKeyword(&storageClass)) |
| return {}; |
| |
| if (auto storageClassSymbol = |
| spirv::symbolizeStorageClass(storageClass)) { |
| storageClassAttr = builder.getI32IntegerAttr( |
| static_cast<uint32_t>(*storageClassSymbol)); |
| } else { |
| parser.emitError(loc, "unknown storage class: ") << storageClass; |
| return {}; |
| } |
| } |
| } |
| |
| if (parser.parseGreater()) |
| return {}; |
| |
| return spirv::InterfaceVarABIAttr::get(descriptorSetAttr, bindingAttr, |
| storageClassAttr); |
| } |
| |
| static Attribute parseVerCapExtAttr(DialectAsmParser &parser) { |
| if (parser.parseLess()) |
| return {}; |
| |
| Builder &builder = parser.getBuilder(); |
| |
| IntegerAttr versionAttr; |
| { |
| auto loc = parser.getCurrentLocation(); |
| StringRef version; |
| if (parser.parseKeyword(&version) || parser.parseComma()) |
| return {}; |
| |
| if (auto versionSymbol = spirv::symbolizeVersion(version)) { |
| versionAttr = |
| builder.getI32IntegerAttr(static_cast<uint32_t>(*versionSymbol)); |
| } else { |
| parser.emitError(loc, "unknown version: ") << version; |
| return {}; |
| } |
| } |
| |
| ArrayAttr capabilitiesAttr; |
| { |
| SmallVector<Attribute, 4> capabilities; |
| SMLoc errorloc; |
| StringRef errorKeyword; |
| |
| auto processCapability = [&](SMLoc loc, StringRef capability) { |
| if (auto capSymbol = spirv::symbolizeCapability(capability)) { |
| capabilities.push_back( |
| builder.getI32IntegerAttr(static_cast<uint32_t>(*capSymbol))); |
| return success(); |
| } |
| return errorloc = loc, errorKeyword = capability, failure(); |
| }; |
| if (parseKeywordList(parser, processCapability) || parser.parseComma()) { |
| if (!errorKeyword.empty()) |
| parser.emitError(errorloc, "unknown capability: ") << errorKeyword; |
| return {}; |
| } |
| |
| capabilitiesAttr = builder.getArrayAttr(capabilities); |
| } |
| |
| ArrayAttr extensionsAttr; |
| { |
| SmallVector<Attribute, 1> extensions; |
| SMLoc errorloc; |
| StringRef errorKeyword; |
| |
| auto processExtension = [&](SMLoc loc, StringRef extension) { |
| if (spirv::symbolizeExtension(extension)) { |
| extensions.push_back(builder.getStringAttr(extension)); |
| return success(); |
| } |
| return errorloc = loc, errorKeyword = extension, failure(); |
| }; |
| if (parseKeywordList(parser, processExtension)) { |
| if (!errorKeyword.empty()) |
| parser.emitError(errorloc, "unknown extension: ") << errorKeyword; |
| return {}; |
| } |
| |
| extensionsAttr = builder.getArrayAttr(extensions); |
| } |
| |
| if (parser.parseGreater()) |
| return {}; |
| |
| return spirv::VerCapExtAttr::get(versionAttr, capabilitiesAttr, |
| extensionsAttr); |
| } |
| |
| /// Parses a spirv::TargetEnvAttr. |
| static Attribute parseTargetEnvAttr(DialectAsmParser &parser) { |
| if (parser.parseLess()) |
| return {}; |
| |
| spirv::VerCapExtAttr tripleAttr; |
| if (parser.parseAttribute(tripleAttr) || parser.parseComma()) |
| return {}; |
| |
| auto clientAPI = spirv::ClientAPI::Unknown; |
| if (succeeded(parser.parseOptionalKeyword("api"))) { |
| if (parser.parseEqual()) |
| return {}; |
| auto loc = parser.getCurrentLocation(); |
| StringRef apiStr; |
| if (parser.parseKeyword(&apiStr)) |
| return {}; |
| if (auto apiSymbol = spirv::symbolizeClientAPI(apiStr)) |
| clientAPI = *apiSymbol; |
| else |
| parser.emitError(loc, "unknown client API: ") << apiStr; |
| if (parser.parseComma()) |
| return {}; |
| } |
| |
| // Parse [vendor[:device-type[:device-id]]] |
| Vendor vendorID = Vendor::Unknown; |
| DeviceType deviceType = DeviceType::Unknown; |
| uint32_t deviceID = spirv::TargetEnvAttr::kUnknownDeviceID; |
| { |
| auto loc = parser.getCurrentLocation(); |
| StringRef vendorStr; |
| if (succeeded(parser.parseOptionalKeyword(&vendorStr))) { |
| if (auto vendorSymbol = spirv::symbolizeVendor(vendorStr)) |
| vendorID = *vendorSymbol; |
| else |
| parser.emitError(loc, "unknown vendor: ") << vendorStr; |
| |
| if (succeeded(parser.parseOptionalColon())) { |
| loc = parser.getCurrentLocation(); |
| StringRef deviceTypeStr; |
| if (parser.parseKeyword(&deviceTypeStr)) |
| return {}; |
| if (auto deviceTypeSymbol = spirv::symbolizeDeviceType(deviceTypeStr)) |
| deviceType = *deviceTypeSymbol; |
| else |
| parser.emitError(loc, "unknown device type: ") << deviceTypeStr; |
| |
| if (succeeded(parser.parseOptionalColon())) { |
| loc = parser.getCurrentLocation(); |
| if (parser.parseInteger(deviceID)) |
| return {}; |
| } |
| } |
| if (parser.parseComma()) |
| return {}; |
| } |
| } |
| |
| ResourceLimitsAttr limitsAttr; |
| if (parser.parseAttribute(limitsAttr) || parser.parseGreater()) |
| return {}; |
| |
| return spirv::TargetEnvAttr::get(tripleAttr, limitsAttr, clientAPI, vendorID, |
| deviceType, deviceID); |
| } |
| |
| Attribute SPIRVDialect::parseAttribute(DialectAsmParser &parser, |
| Type type) const { |
| // SPIR-V attributes are dictionaries so they do not have type. |
| if (type) { |
| parser.emitError(parser.getNameLoc(), "unexpected type"); |
| return {}; |
| } |
| |
| // Parse the kind keyword first. |
| StringRef attrKind; |
| Attribute attr; |
| OptionalParseResult result = |
| generatedAttributeParser(parser, &attrKind, type, attr); |
| if (result.has_value()) |
| return attr; |
| |
| if (attrKind == spirv::TargetEnvAttr::getKindName()) |
| return parseTargetEnvAttr(parser); |
| if (attrKind == spirv::VerCapExtAttr::getKindName()) |
| return parseVerCapExtAttr(parser); |
| if (attrKind == spirv::InterfaceVarABIAttr::getKindName()) |
| return parseInterfaceVarABIAttr(parser); |
| |
| parser.emitError(parser.getNameLoc(), "unknown SPIR-V attribute kind: ") |
| << attrKind; |
| return {}; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Attribute Printing |
| //===----------------------------------------------------------------------===// |
| |
| static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer) { |
| printer << spirv::VerCapExtAttr::getKindName() << "<" |
| << spirv::stringifyVersion(triple.getVersion()) << ", " |
| << llvm::interleaved_array(llvm::map_range( |
| triple.getCapabilities(), spirv::stringifyCapability)) |
| << ", " |
| << llvm::interleaved_array( |
| triple.getExtensionsAttr().getAsValueRange<StringAttr>()) |
| << ">"; |
| } |
| |
| static void print(spirv::TargetEnvAttr targetEnv, DialectAsmPrinter &printer) { |
| printer << spirv::TargetEnvAttr::getKindName() << "<#spirv."; |
| print(targetEnv.getTripleAttr(), printer); |
| auto clientAPI = targetEnv.getClientAPI(); |
| if (clientAPI != spirv::ClientAPI::Unknown) |
| printer << ", api=" << clientAPI; |
| spirv::Vendor vendorID = targetEnv.getVendorID(); |
| spirv::DeviceType deviceType = targetEnv.getDeviceType(); |
| uint32_t deviceID = targetEnv.getDeviceID(); |
| if (vendorID != spirv::Vendor::Unknown) { |
| printer << ", " << spirv::stringifyVendor(vendorID); |
| if (deviceType != spirv::DeviceType::Unknown) { |
| printer << ":" << spirv::stringifyDeviceType(deviceType); |
| if (deviceID != spirv::TargetEnvAttr::kUnknownDeviceID) |
| printer << ":" << deviceID; |
| } |
| } |
| printer << ", " << targetEnv.getResourceLimits() << ">"; |
| } |
| |
| static void print(spirv::InterfaceVarABIAttr interfaceVarABIAttr, |
| DialectAsmPrinter &printer) { |
| printer << spirv::InterfaceVarABIAttr::getKindName() << "<(" |
| << interfaceVarABIAttr.getDescriptorSet() << ", " |
| << interfaceVarABIAttr.getBinding() << ")"; |
| auto storageClass = interfaceVarABIAttr.getStorageClass(); |
| if (storageClass) |
| printer << ", " << spirv::stringifyStorageClass(*storageClass); |
| printer << ">"; |
| } |
| |
| void SPIRVDialect::printAttribute(Attribute attr, |
| DialectAsmPrinter &printer) const { |
| if (succeeded(generatedAttributePrinter(attr, printer))) |
| return; |
| |
| if (auto targetEnv = dyn_cast<TargetEnvAttr>(attr)) |
| print(targetEnv, printer); |
| else if (auto vceAttr = dyn_cast<VerCapExtAttr>(attr)) |
| print(vceAttr, printer); |
| else if (auto interfaceVarABIAttr = dyn_cast<InterfaceVarABIAttr>(attr)) |
| print(interfaceVarABIAttr, printer); |
| else |
| llvm_unreachable("unhandled SPIR-V attribute kind"); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // SPIR-V Dialect |
| //===----------------------------------------------------------------------===// |
| |
| void spirv::SPIRVDialect::registerAttributes() { |
| addAttributes<InterfaceVarABIAttr, TargetEnvAttr, VerCapExtAttr>(); |
| addAttributes< |
| #define GET_ATTRDEF_LIST |
| #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.cpp.inc" |
| >(); |
| } |