diff --git a/mlir/docs/OpDefinitions.md b/mlir/docs/OpDefinitions.md --- a/mlir/docs/OpDefinitions.md +++ b/mlir/docs/OpDefinitions.md @@ -943,6 +943,353 @@ power users; for not-yet-implemented widely-applicable cases, improving the infrastructure is preferable. +### Op availability + +The form/semantics of an op evolve over time. For a dialect that is used in the +middle of conversion flows, its ops are meant to facilitate the conversion, +so backward/forward compatibility is not a main concern. For an edge dialect +that model some external programming model or hardware, its ops are subject to +the same backward/forward compatibility requirements as what they model. +For example, if some accelerator adds a fast convolution implementation in +the second generation, we can introduce an dedicated convolution op for it. +But it can only be used to target the second generation and forward. + +The typical mechanism to define such compatibility requirements is _versioning_. +We can specify the minimal/maximal version under which an op are available. +But there are other ways for controlling compatibility. For example, in SPIR-V, +some ops are available only under certain _capabilities_ or _extensions_. If a +program uses ops that require capabilities/extensions missing in the execution +environment, it's not compatible. + +Generally, these are all _availability_ control mechanisms. MLIR uses a generic +mechanism to support op availability. + +Note that an op may evolve in arbitrary ways. For example, its operands can +support a new type; it can introduce/deprecate some attriubte; its existing enum +attribute may support a new case that require special hardware capability. +Still, they all manifest via whether an _dynamic_ op instance is available for +certain compilation target, because ops are the most basic component for +MLIR conversion. So we call the generic mechanism as op availability in MLIR. + +Op availability is integrated into ODS and tries to follow the same declarative +manner and auto-generate as much code as possible. Under the hood the generated +code uses core mechanisms including op interfaces, op traits, etc. Effectively +it's a layer on top of them, so it offer similar extensibility. The choice of +ODS integration additionally offers single source of truth to drive lots of +boilerplate code generation, across op interfaces, op definitions, and attribute +utility functions, that are cumbersome or difficult to write manually. + +As mentioned before, an op's form/semantics can change arbitrarily. One can +define a v2 version of an op with vastly different semantics and parameters. +It might even make sense to just introduce another op if the difference is too +large. Op availability mechanism cannot support all cases. Instead, it is meant +to cover common cases where we want to still have one op: + +MLIR op availability allows to attach controls to different parts of an op. +Then for a concrete op instance, availability for all parts are considered +to derive a final availability requirements for the instance. This allows us to +keep information where it suits best and potentially share across ops (e.g., +specifying availability on enum attribute cases immediately enables +availability control on all ops containing the enum attribute). + +Right now the following places can have availability specification attached: + +* The op itself: to support cases where the opcode is present or missing + depending on the version/etc. +* Enum attribute case: to suppport cases where op instances using the enum + case requires special version/etc. + +Supporting for the following places might be supported later: + +* Op operands/results: to support cases where operands/results have different + existence and type support in different versions/etc. +* Op attributes: to support cases where attributes have different existence + in different versions/etc. + +Again, the goal is to support common use cases where we still want to have one +op. So it is intentionally conservative. + +If an op has availability controls in any of the above places, the following +corresponding components can be generated from `mlir-tblgen`: + +* Op interface for the availability: via `-gen-avail-interface-decls` and + `-gen-avail-interface-defs`. +* Op interface method implementation: via `-gen-op-defs`. +* Enum availability query utility functions: via `-gen-enum-avail-decls` and + `-gen-enum-avail-defs`. + +Next we explain how to use op availability with examples. + +#### MinVersion and MaxVersion + +It's quite common to see minimal/maximal version requirements on ops. To help +with this common use case, `MinVersionBase` and `MaxVersionBase` are defined in +[`OpBase.td`][OpBase]. It allows us to plug in a dialect-specific versioning +scheme, defined as an `I32EnumAttr`. For example, + +```tablegen +// Define all the known versions for an example dialect. +def Example_V_1_0 : I32EnumAttrCase<"V_1_0", 0, "v1.0">; +def Example_V_1_1 : I32EnumAttrCase<"V_1_1", 1, "v1.1">; +def Example_V_1_2 : I32EnumAttrCase<"V_1_2", 2, "v1.2">; +def Example_V_1_3 : I32EnumAttrCase<"V_1_3", 3, "v1.3">; +def Example_V_1_4 : I32EnumAttrCase<"V_1_4", 3, "v1.4">; + +// Define an IntegerAttr-backed enum attribute including all known versions. +def Example_VersionAttr : I32EnumAttr<"Version", "supported versions", [ + Example_V_1_0, Example_V_1_1, Example_V_1_2, Example_V_1_3, Example_V_1_4]>; + +// Define the MinVersion class. It takes a concrete version (which is an enum +// attribute case) to use. +class Example_MinVersion : MinVersionBase< + "ExampleQueryMinVersionInterface", Example_VersionAttr, min> { + // Specify some description for the generated C++ op interface. + let interfaceDescription = [{ + Querying interface for minimal required version. + }]; + // Specify the namespace for the generated C++ op interface. + let interfaceNamespace = "::mlir::example"; + // MinVersionBase provides defaults for other fields; you can also customize + // them. See the definition of MinVersionBase for details. +} + +// Similarly for MaxVersion. +class Example_MaxVersion : MaxVersionBase< + "ExampleQueryMaxVersionInterface", Example_VersionAttr, max> { + let interfaceDescription = [{ + Querying interface for maximal supported version. + }]; + let interfaceNamespace = "::mlir::example"; +} +``` + +The above defines min and max version requirements for some `example` dialect. +With `mlir-tblgen -gen-avail-interface-{decls|defs}`, two op interfaces are +generated from the above: `mlir::example::ExampleQueryMinVersionInterface` and +`mlir::example::ExampleQueryMaxVersionInterface`. They have a `getMinVersion()` +and `getMaxVersion()` method, respectively, for querying the minimal version and +maximal version requirements for all ops implementing them. + +Then we can use them in ops for the `example` dialect: + +```tablegen +def Example_MinMaxVersionOp : Example_Op<"min_max_version_op"> { + // ... + let availability = [ + Example_MinVersion, + Example_MaxVersion + ]; +} +``` + +The above defines an `example.min_max_version_op` that is introduced in v1.0 and +removed since v1.4. And that's all we need to do for defining the versioning. +`example.min_max_version_op`s' ODS is the single source containing the versioning +information; the rest are automatically generated. + +Concretely, there is no need to manually include the +`mlir::example::EampleQuery{Min|Max}VersionInterface::Trait` in the op trait +list or implement the `get{Min|Max}Version()` method; they are auto inserted or +generated when invoking `mlir-tblgen -gen-op-defs`. + +For the above op, `getMinVersion()` will always return +`mlir::example::Version::V_1_0`, and `getMaxVersion()` will always return +`mlir::example::Version::V_1_3`. + +The op interface and the automatically synthesized concrete implementation can +then be used with other MLIR mechanisms. For example, we can cast a generic +`mlir::Operation` pointer `example::ExampleQueryMinVersionInterface` and +check its `getMinVersion()` to decide if it's allowed in the target. This gives +a generic way to handle all versioned ops in the `example` dialect during +conversion! + +We can also attach version controls on enum attributes: + +```tablegen +def Example_VersionedEnumCaseA : I32EnumAttrCase<"A", 0> { + // No version requirements. +} +def Example_VersionedEnumCaseB : I32EnumAttrCase<"B", 1> { + // Removed since v1.3. + let availability = [Example_MaxVersion]; +} +def Example_VersionedEnumCaseC : I32EnumAttrCase<"C", 2> { + // Added since v1.1. + let availability = [Example_MinVersion]; +} + +def Example_VersionedEnumAttr : I32EnumAttr<"VersionedEnum", "valid enum cases", [ + VersionedEnumCaseA, VersionedEnumCaseB, VersionedEnumCaseC]> { + let cppNamespace = "::mlir::example"; +} + +def Example_OneVersionedAttrOp : Example_Op<"one_versioned_attr_op"> { + let arguments = (ins Example_VersionedEnumAttr:$attr); +let results = (outs); +} + +def Example_MixVersionedAttrOp : Example_Op<"mix_versioned_attr_op"> { + let arguments = (ins + Example_VersionedEnumAttr:$attr1, + Example_VersionedEnumAttr:$attr2, + ... + ); + let results = (outs ...); + + let availability = [ + Example_MinVersion, + Example_MaxVersion + ]; +} +``` + +The above will need `mlir-tblgen -gen-enum-avail-{decls|defs}` to generate the +utility functions for generated C++ enums: + +```c++ +llvm::Optional getMaxVersion( + mlir::example::VersionedEnum value); +llvm::Optional getMinVersion( + mlir::example::VersionedEnum value); +``` + +`example.one_versioned_attr_op` does not have versioning itself; but because it +has an enum attribute that subjects to versioning, it will still automatically +declare and implement the min/max version interface. But here the returned +version depends on the concrete `example.one_versioned_attr_op` instance. For +example, `example.one_versioned_attr_op attr=A` will have `getMinVersion()` and +`getMaxVersion()` to be both `llvm::None`. If `attr=B` then they are +`llvm::None` and `mlir::example::Version::V_1_2`. Similarly, if `attr=C` then +they are `mlir::example::Version::V_1_1` and `llvm::None`. + +`example.mix_versioned_attr_op` has version controls on both itself and two of +its attributes. The final min/max version takes consideration of all pieces. +`attr1=A, attr2=B` will have min/max version as v1.0/v1.2. `attr1=A, attr2=C` +will have min/max version as v1.1/v1.3. `attr1=B attr2=C` will have min/max +version as v1.1/v1.2. + +##### Summary + +There are quite some details in the above. To recap and summarize what are +needed to enable versioning (and whatever custom `Availability` controls you +define for your own dialect, see the next section for details): + +* Define a versioning scheme as an `I32EnumAttr`. +* Annotate ops or enum attributes that has version requirements with + `let availability = [...]`. +* Generate the C++ op interface via `mlir-tblgen -gen-avail-interface-decls` + and `mlir-tblgen -gen-avail-interface-defs` and include them. +* Op interface method implementation will be generated with `mlir-tblgen + -gen-op-defs`. So no extra actions here. +* If you have version controls on enum attribute cases, then generate +* availability query utility functions via `mlir-tblgen -gen-enum-avail-decls` + and `mlir-tblgen -gen-enum-avail-defs` and include them. + +Afterwards all participating ops will implement the min/max interfaces and have +theire concrete implementation synthesized. You can treat them like any ops +implementing op interfaces, e.g., casting to the interface to query versions, +check legality during dialect conversion, etc. + +#### Other availability controls + +Versioning is just one way to control availability. To support others, we can +subclass `Availability`. It requires specifying a few fields for the generated +interface and also logic for deducing final availability results from op +components. Most importantly, we need to define `initializer` as the initial +availability value before considering any part of the op, and `mergeAction` to +specify how a new part's availability is merged into the current deduced +imtermediate availability value. + +There is documentation in the `Availability` class itself. The definitions of +`MinVersionBase`/`MaxVersionBase` can also serve as examples to show how +everything works together. For `MinVersionBase`, we have the following +definition: + +```tablegen +class MinVersionBase + : Availability { + // ... + let queryFnRetType = "llvm::Optional<" # scheme.returnType # ">"; + let queryFnName = "getMinVersion"; + + let mergeAction = "{ " + "if ($overall.hasValue()) { " + "$overall = static_cast<" # scheme.returnType # ">(" + "std::max(*$overall, $instance)); " + "} else { $overall = $instance; }}"; + let initializer = "::llvm::None"; +} +``` + +It generates a method in the op interface with the following signature: + +```c++ +// () +llvm::Optional getMinVersion(); +``` + +The synthesized concrete implementation for `example.mix_versioned_attr_op` is: + +```c++ +llvm::Optional MixVersionedAttrOp::getMinVersion() { + // + llvm::Optional tblgen_overall = ::llvm::None; + { + // : versioning from the op itself + { + if (tblgen_overall.hasValue()) { + tblgen_overall = static_cast( + std::max(*tblgen_overall, mlir::example::Version::V_1_0)); + } else { + tblgen_overall = mlir::example::Version::V_1_0; + } + }; + } + { + auto tblgen_attrVal = this->attr1(); + // Querying versioning requirements from the attribute + auto tblgen_instance = ::mlir::example::getMinVersion(tblgen_attrVal); + if (tblgen_instance) { + // : versioning from attr1 + if (tblgen_overall.hasValue()) { /* ... */ } else { /* ... */ } + }; + } + { + auto tblgen_attrVal = this->attr2(); + // Querying versioning requirements from the attribute + auto tblgen_instance = ::mlir::example::getMinVersion(tblgen_attrVal); + if (tblgen_instance) { + // : versioning from attr1 + if (tblgen_overall.hasValue()) { /* ... */ } else { /* ... */ } + }; + } + return tblgen_overall; +} +``` + +The generated utility methods for querying versioning requirements for +attribute: + +```c++ +// () +llvm::Optional getMinVersion(mlir::example::VersionedEnum value) { + switch (value) { + case mlir::example::VersionedEnum::C: { + // () + return mlir::example::Version(mlir::example::Version::V_1_1); + } + default: break; + } + return llvm::None; +} +``` + +In the above generated code, we use `` to show how each field in the +`Availability` class is used. Reading the source code of how the TableGen C++ +`Availability` wrapper is used and the direct output from `mlir-tblgen` can also +give good hints over how to set them, if you'd like to define a custom +availability control. + ### Generated C++ code [OpDefinitionsGen][OpDefinitionsGen] processes the op definition spec file and diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/SPIRV/IR/CMakeLists.txt --- a/mlir/include/mlir/Dialect/SPIRV/IR/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/SPIRV/IR/CMakeLists.txt @@ -8,8 +8,8 @@ add_dependencies(mlir-headers MLIRSPIRVEnumsIncGen) set(LLVM_TARGET_DEFINITIONS SPIRVBase.td) -mlir_tablegen(SPIRVEnumAvailability.h.inc -gen-spirv-enum-avail-decls) -mlir_tablegen(SPIRVEnumAvailability.cpp.inc -gen-spirv-enum-avail-defs) +mlir_tablegen(SPIRVEnumAvailability.h.inc -gen-enum-avail-decls) +mlir_tablegen(SPIRVEnumAvailability.cpp.inc -gen-enum-avail-defs) mlir_tablegen(SPIRVCapabilityImplication.inc -gen-spirv-capability-implication) add_public_tablegen_target(MLIRSPIRVEnumAvailabilityIncGen) add_dependencies(mlir-headers MLIRSPIRVEnumAvailabilityIncGen) @@ -17,7 +17,6 @@ set(LLVM_TARGET_DEFINITIONS SPIRVOps.td) mlir_tablegen(SPIRVAvailability.h.inc -gen-avail-interface-decls) mlir_tablegen(SPIRVAvailability.cpp.inc -gen-avail-interface-defs) -mlir_tablegen(SPIRVOpAvailabilityImpl.inc -gen-spirv-avail-impls) add_public_tablegen_target(MLIRSPIRVAvailabilityIncGen) add_dependencies(mlir-headers MLIRSPIRVAvailabilityIncGen) diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAvailability.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAvailability.td deleted file mode 100644 --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAvailability.td +++ /dev/null @@ -1,97 +0,0 @@ -//===- SPIRVAvailability.td - Op Availability Base file ----*- tablegen -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef MLIR_DIALECT_SPIRV_IR_AVAILABILITY -#define MLIR_DIALECT_SPIRV_IR_AVAILABILITY - -include "mlir/IR/OpBase.td" - -//===----------------------------------------------------------------------===// -// Op availability definitions -//===----------------------------------------------------------------------===// - -// The base class for defining op availability dimensions. -class Availability { - // The following are fields for controlling the generated C++ OpInterface. - - // The namespace for the generated C++ OpInterface subclass. - string cppNamespace = ?; - // The name for the generated C++ OpInterface subclass. - string interfaceName = ?; - // The documentation for the generated C++ OpInterface subclass. - string interfaceDescription = ""; - - // The following are fields for controlling the query function signature. - - // The query function's return type in the generated C++ OpInterface subclass. - string queryFnRetType = ?; - // The query function's name in the generated C++ OpInterface subclass. - string queryFnName = ?; - - // The following are fields for controlling the query function implementation. - - // The logic for merging two availability requirements. This is used to derive - // the final availability requirement when, for example, an op has two - // operands and these two operands have different availability requirements. - // - // The code should use `$overall` as the placeholder for the final requirement - // and `$instance` for the current availability requirement instance. - code mergeAction = ?; - // The initializer for the final availability requirement. - string initializer = ?; - // An availability instance's type. - string instanceType = ?; - - // The following are fields for a concrete availability instance. - - // The code for preparing a concrete instance. This should be C++ statements - // and will be generated before the `mergeAction` logic. - code instancePreparation = ""; - // The availability requirement carried by a concrete instance. - string instance = ?; -} - -class MinVersionBase - : Availability { - let interfaceName = name; - - let queryFnRetType = "llvm::Optional<" # scheme.returnType # ">"; - let queryFnName = "getMinVersion"; - - let mergeAction = "{ " - "if ($overall.hasValue()) { " - "$overall = static_cast<" # scheme.returnType # ">(" - "std::max(*$overall, $instance)); " - "} else { $overall = $instance; }}"; - let initializer = "::llvm::None"; - let instanceType = scheme.cppNamespace # "::" # scheme.className; - - let instance = scheme.cppNamespace # "::" # scheme.className # "::" # - min.symbol; -} - -class MaxVersionBase - : Availability { - let interfaceName = name; - - let queryFnRetType = "llvm::Optional<" # scheme.returnType # ">"; - let queryFnName = "getMaxVersion"; - - let mergeAction = "{ " - "if ($overall.hasValue()) { " - "$overall = static_cast<" # scheme.returnType # ">(" - "std::min(*$overall, $instance)); " - "} else { $overall = $instance; }}"; - let initializer = "::llvm::None"; - let instanceType = scheme.cppNamespace # "::" # scheme.className; - - let instance = scheme.cppNamespace # "::" # scheme.className # "::" # - max.symbol; -} - -#endif // MLIR_DIALECT_SPIRV_IR_AVAILABILITY diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td @@ -16,7 +16,6 @@ #define MLIR_DIALECT_SPIRV_IR_BASE include "mlir/IR/OpBase.td" -include "mlir/Dialect/SPIRV/IR/SPIRVAvailability.td" //===----------------------------------------------------------------------===// // SPIR-V dialect definitions @@ -233,32 +232,6 @@ let instance = "ref"; } -class SPIRVOpInterface : OpInterface { - let cppNamespace = "::mlir::spirv"; -} -// TODO: the following interfaces definitions are duplicating with the above. -// Remove them once we are able to support dialect-specific contents in ODS. -def QueryMinVersionInterface : SPIRVOpInterface<"QueryMinVersionInterface"> { - let methods = [InterfaceMethod< - "", "::llvm::Optional<::mlir::spirv::Version>", "getMinVersion">]; -} -def QueryMaxVersionInterface : SPIRVOpInterface<"QueryMaxVersionInterface"> { - let methods = [InterfaceMethod< - "", "::llvm::Optional<::mlir::spirv::Version>", "getMaxVersion">]; -} -def QueryExtensionInterface : SPIRVOpInterface<"QueryExtensionInterface"> { - let methods = [InterfaceMethod< - "", - "::llvm::SmallVector<::llvm::ArrayRef<::mlir::spirv::Extension>, 1>", - "getExtensions">]; -} -def QueryCapabilityInterface : SPIRVOpInterface<"QueryCapabilityInterface"> { - let methods = [InterfaceMethod< - "", - "::llvm::SmallVector<::llvm::ArrayRef<::mlir::spirv::Capability>, 1>", - "getCapabilities">]; -} - //===----------------------------------------------------------------------===// // SPIR-V target GPU vendor and device definitions //===----------------------------------------------------------------------===// @@ -399,7 +372,7 @@ def SPV_C_Float64 : I32EnumAttrCase<"Float64", 10>; def SPV_C_Int64 : I32EnumAttrCase<"Int64", 11>; def SPV_C_Groups : I32EnumAttrCase<"Groups", 18> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_ballot]> ]; } @@ -408,162 +381,162 @@ def SPV_C_Sampled1D : I32EnumAttrCase<"Sampled1D", 43>; def SPV_C_SampledBuffer : I32EnumAttrCase<"SampledBuffer", 46>; def SPV_C_GroupNonUniform : I32EnumAttrCase<"GroupNonUniform", 61> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_ShaderLayer : I32EnumAttrCase<"ShaderLayer", 69> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_ShaderViewportIndex : I32EnumAttrCase<"ShaderViewportIndex", 70> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_SubgroupBallotKHR : I32EnumAttrCase<"SubgroupBallotKHR", 4423> { - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_ballot]> ]; } def SPV_C_SubgroupVoteKHR : I32EnumAttrCase<"SubgroupVoteKHR", 4431> { - list availability = [ + let availability = [ Extension<[SPV_KHR_subgroup_vote]> ]; } def SPV_C_StorageBuffer16BitAccess : I32EnumAttrCase<"StorageBuffer16BitAccess", 4433> { - list availability = [ + let availability = [ Extension<[SPV_KHR_16bit_storage]> ]; } def SPV_C_StoragePushConstant16 : I32EnumAttrCase<"StoragePushConstant16", 4435> { - list availability = [ + let availability = [ Extension<[SPV_KHR_16bit_storage]> ]; } def SPV_C_StorageInputOutput16 : I32EnumAttrCase<"StorageInputOutput16", 4436> { - list availability = [ + let availability = [ Extension<[SPV_KHR_16bit_storage]> ]; } def SPV_C_DeviceGroup : I32EnumAttrCase<"DeviceGroup", 4437> { - list availability = [ + let availability = [ Extension<[SPV_KHR_device_group]> ]; } def SPV_C_AtomicStorageOps : I32EnumAttrCase<"AtomicStorageOps", 4445> { - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_atomic_counter_ops]> ]; } def SPV_C_SampleMaskPostDepthCoverage : I32EnumAttrCase<"SampleMaskPostDepthCoverage", 4447> { - list availability = [ + let availability = [ Extension<[SPV_KHR_post_depth_coverage]> ]; } def SPV_C_StorageBuffer8BitAccess : I32EnumAttrCase<"StorageBuffer8BitAccess", 4448> { - list availability = [ + let availability = [ Extension<[SPV_KHR_8bit_storage]> ]; } def SPV_C_StoragePushConstant8 : I32EnumAttrCase<"StoragePushConstant8", 4450> { - list availability = [ + let availability = [ Extension<[SPV_KHR_8bit_storage]> ]; } def SPV_C_DenormPreserve : I32EnumAttrCase<"DenormPreserve", 4464> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]> ]; } def SPV_C_DenormFlushToZero : I32EnumAttrCase<"DenormFlushToZero", 4465> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]> ]; } def SPV_C_SignedZeroInfNanPreserve : I32EnumAttrCase<"SignedZeroInfNanPreserve", 4466> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]> ]; } def SPV_C_RoundingModeRTE : I32EnumAttrCase<"RoundingModeRTE", 4467> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]> ]; } def SPV_C_RoundingModeRTZ : I32EnumAttrCase<"RoundingModeRTZ", 4468> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]> ]; } def SPV_C_ImageFootprintNV : I32EnumAttrCase<"ImageFootprintNV", 5282> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_image_footprint]> ]; } def SPV_C_FragmentBarycentricNV : I32EnumAttrCase<"FragmentBarycentricNV", 5284> { - list availability = [ + let availability = [ Extension<[SPV_NV_fragment_shader_barycentric]> ]; } def SPV_C_ComputeDerivativeGroupQuadsNV : I32EnumAttrCase<"ComputeDerivativeGroupQuadsNV", 5288> { - list availability = [ + let availability = [ Extension<[SPV_NV_compute_shader_derivatives]> ]; } def SPV_C_GroupNonUniformPartitionedNV : I32EnumAttrCase<"GroupNonUniformPartitionedNV", 5297> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_subgroup_partitioned]> ]; } def SPV_C_VulkanMemoryModel : I32EnumAttrCase<"VulkanMemoryModel", 5345> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_VulkanMemoryModelDeviceScope : I32EnumAttrCase<"VulkanMemoryModelDeviceScope", 5346> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_ComputeDerivativeGroupLinearNV : I32EnumAttrCase<"ComputeDerivativeGroupLinearNV", 5350> { - list availability = [ + let availability = [ Extension<[SPV_NV_compute_shader_derivatives]> ]; } def SPV_C_SubgroupShuffleINTEL : I32EnumAttrCase<"SubgroupShuffleINTEL", 5568> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_subgroups]> ]; } def SPV_C_SubgroupBufferBlockIOINTEL : I32EnumAttrCase<"SubgroupBufferBlockIOINTEL", 5569> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_subgroups]> ]; } def SPV_C_SubgroupImageBlockIOINTEL : I32EnumAttrCase<"SubgroupImageBlockIOINTEL", 5570> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_subgroups]> ]; } def SPV_C_SubgroupImageMediaBlockIOINTEL : I32EnumAttrCase<"SubgroupImageMediaBlockIOINTEL", 5579> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_media_block_io]> ]; } def SPV_C_SubgroupAvcMotionEstimationINTEL : I32EnumAttrCase<"SubgroupAvcMotionEstimationINTEL", 5696> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_device_side_avc_motion_estimation]> ]; } def SPV_C_SubgroupAvcMotionEstimationIntraINTEL : I32EnumAttrCase<"SubgroupAvcMotionEstimationIntraINTEL", 5697> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_device_side_avc_motion_estimation]> ]; } def SPV_C_SubgroupAvcMotionEstimationChromaINTEL : I32EnumAttrCase<"SubgroupAvcMotionEstimationChromaINTEL", 5698> { - list availability = [ + let availability = [ Extension<[SPV_INTEL_device_side_avc_motion_estimation]> ]; } @@ -602,67 +575,67 @@ } def SPV_C_NamedBarrier : I32EnumAttrCase<"NamedBarrier", 59> { list implies = [SPV_C_Kernel]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformVote : I32EnumAttrCase<"GroupNonUniformVote", 62> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformArithmetic : I32EnumAttrCase<"GroupNonUniformArithmetic", 63> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformBallot : I32EnumAttrCase<"GroupNonUniformBallot", 64> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformShuffle : I32EnumAttrCase<"GroupNonUniformShuffle", 65> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformShuffleRelative : I32EnumAttrCase<"GroupNonUniformShuffleRelative", 66> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformClustered : I32EnumAttrCase<"GroupNonUniformClustered", 67> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_GroupNonUniformQuad : I32EnumAttrCase<"GroupNonUniformQuad", 68> { list implies = [SPV_C_GroupNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_StorageUniform16 : I32EnumAttrCase<"StorageUniform16", 4434> { list implies = [SPV_C_StorageBuffer16BitAccess]; - list availability = [ + let availability = [ Extension<[SPV_KHR_16bit_storage]> ]; } def SPV_C_UniformAndStorageBuffer8BitAccess : I32EnumAttrCase<"UniformAndStorageBuffer8BitAccess", 4449> { list implies = [SPV_C_StorageBuffer8BitAccess]; - list availability = [ + let availability = [ Extension<[SPV_KHR_8bit_storage]> ]; } def SPV_C_UniformTexelBufferArrayDynamicIndexing : I32EnumAttrCase<"UniformTexelBufferArrayDynamicIndexing", 5304> { list implies = [SPV_C_SampledBuffer]; - list availability = [ + let availability = [ MinVersion ]; } @@ -749,157 +722,157 @@ } def SPV_C_SubgroupDispatch : I32EnumAttrCase<"SubgroupDispatch", 58> { list implies = [SPV_C_DeviceEnqueue]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_PipeStorage : I32EnumAttrCase<"PipeStorage", 60> { list implies = [SPV_C_Pipes]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_DrawParameters : I32EnumAttrCase<"DrawParameters", 4427> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_draw_parameters]> ]; } def SPV_C_MultiView : I32EnumAttrCase<"MultiView", 4439> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_KHR_multiview]> ]; } def SPV_C_VariablePointersStorageBuffer : I32EnumAttrCase<"VariablePointersStorageBuffer", 4441> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_KHR_variable_pointers]> ]; } def SPV_C_Float16ImageAMD : I32EnumAttrCase<"Float16ImageAMD", 5008> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_AMD_gpu_shader_half_float_fetch]> ]; } def SPV_C_ImageGatherBiasLodAMD : I32EnumAttrCase<"ImageGatherBiasLodAMD", 5009> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_AMD_texture_gather_bias_lod]> ]; } def SPV_C_FragmentMaskAMD : I32EnumAttrCase<"FragmentMaskAMD", 5010> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_fragment_mask]> ]; } def SPV_C_StencilExportEXT : I32EnumAttrCase<"StencilExportEXT", 5013> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_shader_stencil_export]> ]; } def SPV_C_ImageReadWriteLodAMD : I32EnumAttrCase<"ImageReadWriteLodAMD", 5015> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_image_load_store_lod]> ]; } def SPV_C_ShaderClockKHR : I32EnumAttrCase<"ShaderClockKHR", 5055> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_clock]> ]; } def SPV_C_FragmentFullyCoveredEXT : I32EnumAttrCase<"FragmentFullyCoveredEXT", 5265> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_fully_covered]> ]; } def SPV_C_MeshShadingNV : I32EnumAttrCase<"MeshShadingNV", 5266> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]> ]; } def SPV_C_FragmentDensityEXT : I32EnumAttrCase<"FragmentDensityEXT", 5291> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_invocation_density, SPV_NV_shading_rate]> ]; } def SPV_C_ShaderNonUniform : I32EnumAttrCase<"ShaderNonUniform", 5301> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_RuntimeDescriptorArray : I32EnumAttrCase<"RuntimeDescriptorArray", 5302> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_StorageTexelBufferArrayDynamicIndexing : I32EnumAttrCase<"StorageTexelBufferArrayDynamicIndexing", 5305> { list implies = [SPV_C_ImageBuffer]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_RayTracingNV : I32EnumAttrCase<"RayTracingNV", 5340> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]> ]; } def SPV_C_PhysicalStorageBufferAddresses : I32EnumAttrCase<"PhysicalStorageBufferAddresses", 5347> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer]> ]; } def SPV_C_CooperativeMatrixNV : I32EnumAttrCase<"CooperativeMatrixNV", 5357> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_NV_cooperative_matrix]> ]; } def SPV_C_FragmentShaderSampleInterlockEXT : I32EnumAttrCase<"FragmentShaderSampleInterlockEXT", 5363> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]> ]; } def SPV_C_FragmentShaderShadingRateInterlockEXT : I32EnumAttrCase<"FragmentShaderShadingRateInterlockEXT", 5372> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]> ]; } def SPV_C_ShaderSMBuiltinsNV : I32EnumAttrCase<"ShaderSMBuiltinsNV", 5373> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_NV_shader_sm_builtins]> ]; } def SPV_C_FragmentShaderPixelInterlockEXT : I32EnumAttrCase<"FragmentShaderPixelInterlockEXT", 5378> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]> ]; } def SPV_C_DemoteToHelperInvocationEXT : I32EnumAttrCase<"DemoteToHelperInvocationEXT", 5379> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_EXT_demote_to_helper_invocation]> ]; } def SPV_C_IntegerFunctions2INTEL : I32EnumAttrCase<"IntegerFunctions2INTEL", 5584> { list implies = [SPV_C_Shader]; - list availability = [ + let availability = [ Extension<[SPV_INTEL_shader_integer_functions2]> ]; } @@ -923,91 +896,91 @@ } def SPV_C_VariablePointers : I32EnumAttrCase<"VariablePointers", 4442> { list implies = [SPV_C_VariablePointersStorageBuffer]; - list availability = [ + let availability = [ Extension<[SPV_KHR_variable_pointers]> ]; } def SPV_C_SampleMaskOverrideCoverageNV : I32EnumAttrCase<"SampleMaskOverrideCoverageNV", 5249> { list implies = [SPV_C_SampleRateShading]; - list availability = [ + let availability = [ Extension<[SPV_NV_sample_mask_override_coverage]> ]; } def SPV_C_GeometryShaderPassthroughNV : I32EnumAttrCase<"GeometryShaderPassthroughNV", 5251> { list implies = [SPV_C_Geometry]; - list availability = [ + let availability = [ Extension<[SPV_NV_geometry_shader_passthrough]> ]; } def SPV_C_PerViewAttributesNV : I32EnumAttrCase<"PerViewAttributesNV", 5260> { list implies = [SPV_C_MultiView]; - list availability = [ + let availability = [ Extension<[SPV_NVX_multiview_per_view_attributes]> ]; } def SPV_C_InputAttachmentArrayDynamicIndexing : I32EnumAttrCase<"InputAttachmentArrayDynamicIndexing", 5303> { list implies = [SPV_C_InputAttachment]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_UniformBufferArrayNonUniformIndexing : I32EnumAttrCase<"UniformBufferArrayNonUniformIndexing", 5306> { list implies = [SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_SampledImageArrayNonUniformIndexing : I32EnumAttrCase<"SampledImageArrayNonUniformIndexing", 5307> { list implies = [SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_StorageBufferArrayNonUniformIndexing : I32EnumAttrCase<"StorageBufferArrayNonUniformIndexing", 5308> { list implies = [SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_StorageImageArrayNonUniformIndexing : I32EnumAttrCase<"StorageImageArrayNonUniformIndexing", 5309> { list implies = [SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_InputAttachmentArrayNonUniformIndexing : I32EnumAttrCase<"InputAttachmentArrayNonUniformIndexing", 5310> { list implies = [SPV_C_InputAttachment, SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_UniformTexelBufferArrayNonUniformIndexing : I32EnumAttrCase<"UniformTexelBufferArrayNonUniformIndexing", 5311> { list implies = [SPV_C_SampledBuffer, SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_StorageTexelBufferArrayNonUniformIndexing : I32EnumAttrCase<"StorageTexelBufferArrayNonUniformIndexing", 5312> { list implies = [SPV_C_ImageBuffer, SPV_C_ShaderNonUniform]; - list availability = [ + let availability = [ MinVersion ]; } def SPV_C_ShaderViewportIndexLayerEXT : I32EnumAttrCase<"ShaderViewportIndexLayerEXT", 5254> { list implies = [SPV_C_MultiViewport]; - list availability = [ + let availability = [ Extension<[SPV_EXT_shader_viewport_index_layer]> ]; } def SPV_C_ShaderViewportMaskNV : I32EnumAttrCase<"ShaderViewportMaskNV", 5255> { list implies = [SPV_C_ShaderViewportIndexLayerEXT]; - list availability = [ + let availability = [ Extension<[SPV_NV_viewport_array2]> ]; } def SPV_C_ShaderStereoViewNV : I32EnumAttrCase<"ShaderStereoViewNV", 5259> { list implies = [SPV_C_ShaderViewportMaskNV]; - list availability = [ + let availability = [ Extension<[SPV_NV_stereo_view_rendering]> ]; } @@ -1079,17 +1052,17 @@ def SPV_AM_Logical : I32EnumAttrCase<"Logical", 0>; def SPV_AM_Physical32 : I32EnumAttrCase<"Physical32", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Addresses]> ]; } def SPV_AM_Physical64 : I32EnumAttrCase<"Physical64", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Addresses]> ]; } def SPV_AM_PhysicalStorageBuffer64 : I32EnumAttrCase<"PhysicalStorageBuffer64", 5348> { - list availability = [ + let availability = [ Extension<[SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer]>, Capability<[SPV_C_PhysicalStorageBufferAddresses]> ]; @@ -1102,112 +1075,112 @@ ]>; def SPV_BI_Position : I32EnumAttrCase<"Position", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_PointSize : I32EnumAttrCase<"PointSize", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_ClipDistance : I32EnumAttrCase<"ClipDistance", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_ClipDistance]> ]; } def SPV_BI_CullDistance : I32EnumAttrCase<"CullDistance", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_CullDistance]> ]; } def SPV_BI_VertexId : I32EnumAttrCase<"VertexId", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_InstanceId : I32EnumAttrCase<"InstanceId", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_PrimitiveId : I32EnumAttrCase<"PrimitiveId", 7> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_RayTracingNV, SPV_C_Tessellation]> ]; } def SPV_BI_InvocationId : I32EnumAttrCase<"InvocationId", 8> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_Tessellation]> ]; } def SPV_BI_Layer : I32EnumAttrCase<"Layer", 9> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_ShaderLayer, SPV_C_ShaderViewportIndexLayerEXT]> ]; } def SPV_BI_ViewportIndex : I32EnumAttrCase<"ViewportIndex", 10> { - list availability = [ + let availability = [ Capability<[SPV_C_MultiViewport, SPV_C_ShaderViewportIndex, SPV_C_ShaderViewportIndexLayerEXT]> ]; } def SPV_BI_TessLevelOuter : I32EnumAttrCase<"TessLevelOuter", 11> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_BI_TessLevelInner : I32EnumAttrCase<"TessLevelInner", 12> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_BI_TessCoord : I32EnumAttrCase<"TessCoord", 13> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_BI_PatchVertices : I32EnumAttrCase<"PatchVertices", 14> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_BI_FragCoord : I32EnumAttrCase<"FragCoord", 15> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_PointCoord : I32EnumAttrCase<"PointCoord", 16> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_FrontFacing : I32EnumAttrCase<"FrontFacing", 17> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_SampleId : I32EnumAttrCase<"SampleId", 18> { - list availability = [ + let availability = [ Capability<[SPV_C_SampleRateShading]> ]; } def SPV_BI_SamplePosition : I32EnumAttrCase<"SamplePosition", 19> { - list availability = [ + let availability = [ Capability<[SPV_C_SampleRateShading]> ]; } def SPV_BI_SampleMask : I32EnumAttrCase<"SampleMask", 20> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_FragDepth : I32EnumAttrCase<"FragDepth", 22> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_HelperInvocation : I32EnumAttrCase<"HelperInvocation", 23> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } @@ -1218,383 +1191,383 @@ def SPV_BI_GlobalInvocationId : I32EnumAttrCase<"GlobalInvocationId", 28>; def SPV_BI_LocalInvocationIndex : I32EnumAttrCase<"LocalInvocationIndex", 29>; def SPV_BI_WorkDim : I32EnumAttrCase<"WorkDim", 30> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_GlobalSize : I32EnumAttrCase<"GlobalSize", 31> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_EnqueuedWorkgroupSize : I32EnumAttrCase<"EnqueuedWorkgroupSize", 32> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_GlobalOffset : I32EnumAttrCase<"GlobalOffset", 33> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_GlobalLinearId : I32EnumAttrCase<"GlobalLinearId", 34> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_SubgroupSize : I32EnumAttrCase<"SubgroupSize", 36> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniform, SPV_C_Kernel, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_SubgroupMaxSize : I32EnumAttrCase<"SubgroupMaxSize", 37> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_NumSubgroups : I32EnumAttrCase<"NumSubgroups", 38> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniform, SPV_C_Kernel]> ]; } def SPV_BI_NumEnqueuedSubgroups : I32EnumAttrCase<"NumEnqueuedSubgroups", 39> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_BI_SubgroupId : I32EnumAttrCase<"SubgroupId", 40> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniform, SPV_C_Kernel]> ]; } def SPV_BI_SubgroupLocalInvocationId : I32EnumAttrCase<"SubgroupLocalInvocationId", 41> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniform, SPV_C_Kernel, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_VertexIndex : I32EnumAttrCase<"VertexIndex", 42> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_InstanceIndex : I32EnumAttrCase<"InstanceIndex", 43> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_BI_SubgroupEqMask : I32EnumAttrCase<"SubgroupEqMask", 4416> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformBallot, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_SubgroupGeMask : I32EnumAttrCase<"SubgroupGeMask", 4417> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformBallot, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_SubgroupGtMask : I32EnumAttrCase<"SubgroupGtMask", 4418> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformBallot, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_SubgroupLeMask : I32EnumAttrCase<"SubgroupLeMask", 4419> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformBallot, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_SubgroupLtMask : I32EnumAttrCase<"SubgroupLtMask", 4420> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformBallot, SPV_C_SubgroupBallotKHR]> ]; } def SPV_BI_BaseVertex : I32EnumAttrCase<"BaseVertex", 4424> { - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_draw_parameters]>, Capability<[SPV_C_DrawParameters]> ]; } def SPV_BI_BaseInstance : I32EnumAttrCase<"BaseInstance", 4425> { - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_draw_parameters]>, Capability<[SPV_C_DrawParameters]> ]; } def SPV_BI_DrawIndex : I32EnumAttrCase<"DrawIndex", 4426> { - list availability = [ + let availability = [ Extension<[SPV_KHR_shader_draw_parameters, SPV_NV_mesh_shader]>, Capability<[SPV_C_DrawParameters, SPV_C_MeshShadingNV]> ]; } def SPV_BI_DeviceIndex : I32EnumAttrCase<"DeviceIndex", 4438> { - list availability = [ + let availability = [ Extension<[SPV_KHR_device_group]>, Capability<[SPV_C_DeviceGroup]> ]; } def SPV_BI_ViewIndex : I32EnumAttrCase<"ViewIndex", 4440> { - list availability = [ + let availability = [ Extension<[SPV_KHR_multiview]>, Capability<[SPV_C_MultiView]> ]; } def SPV_BI_BaryCoordNoPerspAMD : I32EnumAttrCase<"BaryCoordNoPerspAMD", 4992> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordNoPerspCentroidAMD : I32EnumAttrCase<"BaryCoordNoPerspCentroidAMD", 4993> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordNoPerspSampleAMD : I32EnumAttrCase<"BaryCoordNoPerspSampleAMD", 4994> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordSmoothAMD : I32EnumAttrCase<"BaryCoordSmoothAMD", 4995> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordSmoothCentroidAMD : I32EnumAttrCase<"BaryCoordSmoothCentroidAMD", 4996> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordSmoothSampleAMD : I32EnumAttrCase<"BaryCoordSmoothSampleAMD", 4997> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_BaryCoordPullModelAMD : I32EnumAttrCase<"BaryCoordPullModelAMD", 4998> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_BI_FragStencilRefEXT : I32EnumAttrCase<"FragStencilRefEXT", 5014> { - list availability = [ + let availability = [ Extension<[SPV_EXT_shader_stencil_export]>, Capability<[SPV_C_StencilExportEXT]> ]; } def SPV_BI_ViewportMaskNV : I32EnumAttrCase<"ViewportMaskNV", 5253> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader, SPV_NV_viewport_array2]>, Capability<[SPV_C_MeshShadingNV, SPV_C_ShaderViewportMaskNV]> ]; } def SPV_BI_SecondaryPositionNV : I32EnumAttrCase<"SecondaryPositionNV", 5257> { - list availability = [ + let availability = [ Extension<[SPV_NV_stereo_view_rendering]>, Capability<[SPV_C_ShaderStereoViewNV]> ]; } def SPV_BI_SecondaryViewportMaskNV : I32EnumAttrCase<"SecondaryViewportMaskNV", 5258> { - list availability = [ + let availability = [ Extension<[SPV_NV_stereo_view_rendering]>, Capability<[SPV_C_ShaderStereoViewNV]> ]; } def SPV_BI_PositionPerViewNV : I32EnumAttrCase<"PositionPerViewNV", 5261> { - list availability = [ + let availability = [ Extension<[SPV_NVX_multiview_per_view_attributes, SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV, SPV_C_PerViewAttributesNV]> ]; } def SPV_BI_ViewportMaskPerViewNV : I32EnumAttrCase<"ViewportMaskPerViewNV", 5262> { - list availability = [ + let availability = [ Extension<[SPV_NVX_multiview_per_view_attributes, SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV, SPV_C_PerViewAttributesNV]> ]; } def SPV_BI_FullyCoveredEXT : I32EnumAttrCase<"FullyCoveredEXT", 5264> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_fully_covered]>, Capability<[SPV_C_FragmentFullyCoveredEXT]> ]; } def SPV_BI_TaskCountNV : I32EnumAttrCase<"TaskCountNV", 5274> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_PrimitiveCountNV : I32EnumAttrCase<"PrimitiveCountNV", 5275> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_PrimitiveIndicesNV : I32EnumAttrCase<"PrimitiveIndicesNV", 5276> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_ClipDistancePerViewNV : I32EnumAttrCase<"ClipDistancePerViewNV", 5277> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_CullDistancePerViewNV : I32EnumAttrCase<"CullDistancePerViewNV", 5278> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_LayerPerViewNV : I32EnumAttrCase<"LayerPerViewNV", 5279> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_MeshViewCountNV : I32EnumAttrCase<"MeshViewCountNV", 5280> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_MeshViewIndicesNV : I32EnumAttrCase<"MeshViewIndicesNV", 5281> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_BI_BaryCoordNV : I32EnumAttrCase<"BaryCoordNV", 5286> { - list availability = [ + let availability = [ Extension<[SPV_NV_fragment_shader_barycentric]>, Capability<[SPV_C_FragmentBarycentricNV]> ]; } def SPV_BI_BaryCoordNoPerspNV : I32EnumAttrCase<"BaryCoordNoPerspNV", 5287> { - list availability = [ + let availability = [ Extension<[SPV_NV_fragment_shader_barycentric]>, Capability<[SPV_C_FragmentBarycentricNV]> ]; } def SPV_BI_FragSizeEXT : I32EnumAttrCase<"FragSizeEXT", 5292> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_invocation_density, SPV_NV_shading_rate]>, Capability<[SPV_C_FragmentDensityEXT]> ]; } def SPV_BI_FragInvocationCountEXT : I32EnumAttrCase<"FragInvocationCountEXT", 5293> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_invocation_density, SPV_NV_shading_rate]>, Capability<[SPV_C_FragmentDensityEXT]> ]; } def SPV_BI_LaunchIdNV : I32EnumAttrCase<"LaunchIdNV", 5319> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_LaunchSizeNV : I32EnumAttrCase<"LaunchSizeNV", 5320> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_WorldRayOriginNV : I32EnumAttrCase<"WorldRayOriginNV", 5321> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_WorldRayDirectionNV : I32EnumAttrCase<"WorldRayDirectionNV", 5322> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_ObjectRayOriginNV : I32EnumAttrCase<"ObjectRayOriginNV", 5323> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_ObjectRayDirectionNV : I32EnumAttrCase<"ObjectRayDirectionNV", 5324> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_RayTminNV : I32EnumAttrCase<"RayTminNV", 5325> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_RayTmaxNV : I32EnumAttrCase<"RayTmaxNV", 5326> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_InstanceCustomIndexNV : I32EnumAttrCase<"InstanceCustomIndexNV", 5327> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_ObjectToWorldNV : I32EnumAttrCase<"ObjectToWorldNV", 5330> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_WorldToObjectNV : I32EnumAttrCase<"WorldToObjectNV", 5331> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_HitTNV : I32EnumAttrCase<"HitTNV", 5332> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_HitKindNV : I32EnumAttrCase<"HitKindNV", 5333> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_IncomingRayFlagsNV : I32EnumAttrCase<"IncomingRayFlagsNV", 5351> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_BI_WarpsPerSMNV : I32EnumAttrCase<"WarpsPerSMNV", 5374> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_sm_builtins]>, Capability<[SPV_C_ShaderSMBuiltinsNV]> ]; } def SPV_BI_SMCountNV : I32EnumAttrCase<"SMCountNV", 5375> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_sm_builtins]>, Capability<[SPV_C_ShaderSMBuiltinsNV]> ]; } def SPV_BI_WarpIDNV : I32EnumAttrCase<"WarpIDNV", 5376> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_sm_builtins]>, Capability<[SPV_C_ShaderSMBuiltinsNV]> ]; } def SPV_BI_SMIDNV : I32EnumAttrCase<"SMIDNV", 5377> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_sm_builtins]>, Capability<[SPV_C_ShaderSMBuiltinsNV]> ]; @@ -1637,89 +1610,89 @@ ]>; def SPV_D_RelaxedPrecision : I32EnumAttrCase<"RelaxedPrecision", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_SpecId : I32EnumAttrCase<"SpecId", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel, SPV_C_Shader]> ]; } def SPV_D_Block : I32EnumAttrCase<"Block", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_BufferBlock : I32EnumAttrCase<"BufferBlock", 3> { - list availability = [ + let availability = [ MaxVersion, Capability<[SPV_C_Shader]> ]; } def SPV_D_RowMajor : I32EnumAttrCase<"RowMajor", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_Matrix]> ]; } def SPV_D_ColMajor : I32EnumAttrCase<"ColMajor", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_Matrix]> ]; } def SPV_D_ArrayStride : I32EnumAttrCase<"ArrayStride", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_MatrixStride : I32EnumAttrCase<"MatrixStride", 7> { - list availability = [ + let availability = [ Capability<[SPV_C_Matrix]> ]; } def SPV_D_GLSLShared : I32EnumAttrCase<"GLSLShared", 8> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_GLSLPacked : I32EnumAttrCase<"GLSLPacked", 9> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_CPacked : I32EnumAttrCase<"CPacked", 10> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_D_BuiltIn : I32EnumAttrCase<"BuiltIn", 11>; def SPV_D_NoPerspective : I32EnumAttrCase<"NoPerspective", 13> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Flat : I32EnumAttrCase<"Flat", 14> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Patch : I32EnumAttrCase<"Patch", 15> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_D_Centroid : I32EnumAttrCase<"Centroid", 16> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Sample : I32EnumAttrCase<"Sample", 17> { - list availability = [ + let availability = [ Capability<[SPV_C_SampleRateShading]> ]; } def SPV_D_Invariant : I32EnumAttrCase<"Invariant", 18> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } @@ -1727,7 +1700,7 @@ def SPV_D_Aliased : I32EnumAttrCase<"Aliased", 20>; def SPV_D_Volatile : I32EnumAttrCase<"Volatile", 21>; def SPV_D_Constant : I32EnumAttrCase<"Constant", 22> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } @@ -1735,207 +1708,207 @@ def SPV_D_NonWritable : I32EnumAttrCase<"NonWritable", 24>; def SPV_D_NonReadable : I32EnumAttrCase<"NonReadable", 25>; def SPV_D_Uniform : I32EnumAttrCase<"Uniform", 26> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_UniformId : I32EnumAttrCase<"UniformId", 27> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Shader]> ]; } def SPV_D_SaturatedConversion : I32EnumAttrCase<"SaturatedConversion", 28> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_D_Stream : I32EnumAttrCase<"Stream", 29> { - list availability = [ + let availability = [ Capability<[SPV_C_GeometryStreams]> ]; } def SPV_D_Location : I32EnumAttrCase<"Location", 30> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Component : I32EnumAttrCase<"Component", 31> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Index : I32EnumAttrCase<"Index", 32> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Binding : I32EnumAttrCase<"Binding", 33> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_DescriptorSet : I32EnumAttrCase<"DescriptorSet", 34> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_Offset : I32EnumAttrCase<"Offset", 35> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_XfbBuffer : I32EnumAttrCase<"XfbBuffer", 36> { - list availability = [ + let availability = [ Capability<[SPV_C_TransformFeedback]> ]; } def SPV_D_XfbStride : I32EnumAttrCase<"XfbStride", 37> { - list availability = [ + let availability = [ Capability<[SPV_C_TransformFeedback]> ]; } def SPV_D_FuncParamAttr : I32EnumAttrCase<"FuncParamAttr", 38> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_D_FPRoundingMode : I32EnumAttrCase<"FPRoundingMode", 39>; def SPV_D_FPFastMathMode : I32EnumAttrCase<"FPFastMathMode", 40> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_D_LinkageAttributes : I32EnumAttrCase<"LinkageAttributes", 41> { - list availability = [ + let availability = [ Capability<[SPV_C_Linkage]> ]; } def SPV_D_NoContraction : I32EnumAttrCase<"NoContraction", 42> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_D_InputAttachmentIndex : I32EnumAttrCase<"InputAttachmentIndex", 43> { - list availability = [ + let availability = [ Capability<[SPV_C_InputAttachment]> ]; } def SPV_D_Alignment : I32EnumAttrCase<"Alignment", 44> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_D_MaxByteOffset : I32EnumAttrCase<"MaxByteOffset", 45> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Addresses]> ]; } def SPV_D_AlignmentId : I32EnumAttrCase<"AlignmentId", 46> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Kernel]> ]; } def SPV_D_MaxByteOffsetId : I32EnumAttrCase<"MaxByteOffsetId", 47> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Addresses]> ]; } def SPV_D_NoSignedWrap : I32EnumAttrCase<"NoSignedWrap", 4469> { - list availability = [ + let availability = [ Extension<[SPV_KHR_no_integer_wrap_decoration]> ]; } def SPV_D_NoUnsignedWrap : I32EnumAttrCase<"NoUnsignedWrap", 4470> { - list availability = [ + let availability = [ Extension<[SPV_KHR_no_integer_wrap_decoration]> ]; } def SPV_D_ExplicitInterpAMD : I32EnumAttrCase<"ExplicitInterpAMD", 4999> { - list availability = [ + let availability = [ Extension<[SPV_AMD_shader_explicit_vertex_parameter]> ]; } def SPV_D_OverrideCoverageNV : I32EnumAttrCase<"OverrideCoverageNV", 5248> { - list availability = [ + let availability = [ Extension<[SPV_NV_sample_mask_override_coverage]>, Capability<[SPV_C_SampleMaskOverrideCoverageNV]> ]; } def SPV_D_PassthroughNV : I32EnumAttrCase<"PassthroughNV", 5250> { - list availability = [ + let availability = [ Extension<[SPV_NV_geometry_shader_passthrough]>, Capability<[SPV_C_GeometryShaderPassthroughNV]> ]; } def SPV_D_ViewportRelativeNV : I32EnumAttrCase<"ViewportRelativeNV", 5252> { - list availability = [ + let availability = [ Capability<[SPV_C_ShaderViewportMaskNV]> ]; } def SPV_D_SecondaryViewportRelativeNV : I32EnumAttrCase<"SecondaryViewportRelativeNV", 5256> { - list availability = [ + let availability = [ Extension<[SPV_NV_stereo_view_rendering]>, Capability<[SPV_C_ShaderStereoViewNV]> ]; } def SPV_D_PerPrimitiveNV : I32EnumAttrCase<"PerPrimitiveNV", 5271> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_D_PerViewNV : I32EnumAttrCase<"PerViewNV", 5272> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_D_PerTaskNV : I32EnumAttrCase<"PerTaskNV", 5273> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_D_PerVertexNV : I32EnumAttrCase<"PerVertexNV", 5285> { - list availability = [ + let availability = [ Extension<[SPV_NV_fragment_shader_barycentric]>, Capability<[SPV_C_FragmentBarycentricNV]> ]; } def SPV_D_NonUniform : I32EnumAttrCase<"NonUniform", 5300> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_ShaderNonUniform]> ]; } def SPV_D_RestrictPointer : I32EnumAttrCase<"RestrictPointer", 5355> { - list availability = [ + let availability = [ Extension<[SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer]>, Capability<[SPV_C_PhysicalStorageBufferAddresses]> ]; } def SPV_D_AliasedPointer : I32EnumAttrCase<"AliasedPointer", 5356> { - list availability = [ + let availability = [ Extension<[SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer]>, Capability<[SPV_C_PhysicalStorageBufferAddresses]> ]; } def SPV_D_CounterBuffer : I32EnumAttrCase<"CounterBuffer", 5634> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_D_UserSemantic : I32EnumAttrCase<"UserSemantic", 5635> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_D_UserTypeGOOGLE : I32EnumAttrCase<"UserTypeGOOGLE", 5636> { - list availability = [ + let availability = [ Extension<[SPV_GOOGLE_user_type]> ]; } @@ -1963,33 +1936,33 @@ ]>; def SPV_D_1D : I32EnumAttrCase<"Dim1D", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Image1D, SPV_C_Sampled1D]> ]; } def SPV_D_2D : I32EnumAttrCase<"Dim2D", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_ImageMSArray, SPV_C_Kernel, SPV_C_Shader]> ]; } def SPV_D_3D : I32EnumAttrCase<"Dim3D", 2>; def SPV_D_Cube : I32EnumAttrCase<"Cube", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_ImageCubeArray, SPV_C_Shader]> ]; } def SPV_D_Rect : I32EnumAttrCase<"Rect", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_ImageRect, SPV_C_SampledRect]> ]; } def SPV_D_Buffer : I32EnumAttrCase<"Buffer", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_ImageBuffer, SPV_C_SampledBuffer]> ]; } def SPV_D_SubpassData : I32EnumAttrCase<"SubpassData", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_InputAttachment]> ]; } @@ -2001,301 +1974,301 @@ ]>; def SPV_EM_Invocations : I32EnumAttrCase<"Invocations", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_SpacingEqual : I32EnumAttrCase<"SpacingEqual", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_SpacingFractionalEven : I32EnumAttrCase<"SpacingFractionalEven", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_SpacingFractionalOdd : I32EnumAttrCase<"SpacingFractionalOdd", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_VertexOrderCw : I32EnumAttrCase<"VertexOrderCw", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_VertexOrderCcw : I32EnumAttrCase<"VertexOrderCcw", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_PixelCenterInteger : I32EnumAttrCase<"PixelCenterInteger", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_OriginUpperLeft : I32EnumAttrCase<"OriginUpperLeft", 7> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_OriginLowerLeft : I32EnumAttrCase<"OriginLowerLeft", 8> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_EarlyFragmentTests : I32EnumAttrCase<"EarlyFragmentTests", 9> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_PointMode : I32EnumAttrCase<"PointMode", 10> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_Xfb : I32EnumAttrCase<"Xfb", 11> { - list availability = [ + let availability = [ Capability<[SPV_C_TransformFeedback]> ]; } def SPV_EM_DepthReplacing : I32EnumAttrCase<"DepthReplacing", 12> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_DepthGreater : I32EnumAttrCase<"DepthGreater", 14> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_DepthLess : I32EnumAttrCase<"DepthLess", 15> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_DepthUnchanged : I32EnumAttrCase<"DepthUnchanged", 16> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_LocalSize : I32EnumAttrCase<"LocalSize", 17>; def SPV_EM_LocalSizeHint : I32EnumAttrCase<"LocalSizeHint", 18> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_EM_InputPoints : I32EnumAttrCase<"InputPoints", 19> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_InputLines : I32EnumAttrCase<"InputLines", 20> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_InputLinesAdjacency : I32EnumAttrCase<"InputLinesAdjacency", 21> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_Triangles : I32EnumAttrCase<"Triangles", 22> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_Tessellation]> ]; } def SPV_EM_InputTrianglesAdjacency : I32EnumAttrCase<"InputTrianglesAdjacency", 23> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_Quads : I32EnumAttrCase<"Quads", 24> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_Isolines : I32EnumAttrCase<"Isolines", 25> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_OutputVertices : I32EnumAttrCase<"OutputVertices", 26> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_MeshShadingNV, SPV_C_Tessellation]> ]; } def SPV_EM_OutputPoints : I32EnumAttrCase<"OutputPoints", 27> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry, SPV_C_MeshShadingNV]> ]; } def SPV_EM_OutputLineStrip : I32EnumAttrCase<"OutputLineStrip", 28> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_OutputTriangleStrip : I32EnumAttrCase<"OutputTriangleStrip", 29> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_VecTypeHint : I32EnumAttrCase<"VecTypeHint", 30> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_EM_ContractionOff : I32EnumAttrCase<"ContractionOff", 31> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_EM_Initializer : I32EnumAttrCase<"Initializer", 33> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Kernel]> ]; } def SPV_EM_Finalizer : I32EnumAttrCase<"Finalizer", 34> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Kernel]> ]; } def SPV_EM_SubgroupSize : I32EnumAttrCase<"SubgroupSize", 35> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_SubgroupDispatch]> ]; } def SPV_EM_SubgroupsPerWorkgroup : I32EnumAttrCase<"SubgroupsPerWorkgroup", 36> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_SubgroupDispatch]> ]; } def SPV_EM_SubgroupsPerWorkgroupId : I32EnumAttrCase<"SubgroupsPerWorkgroupId", 37> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_SubgroupDispatch]> ]; } def SPV_EM_LocalSizeId : I32EnumAttrCase<"LocalSizeId", 38> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_EM_LocalSizeHintId : I32EnumAttrCase<"LocalSizeHintId", 39> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_Kernel]> ]; } def SPV_EM_PostDepthCoverage : I32EnumAttrCase<"PostDepthCoverage", 4446> { - list availability = [ + let availability = [ Extension<[SPV_KHR_post_depth_coverage]>, Capability<[SPV_C_SampleMaskPostDepthCoverage]> ]; } def SPV_EM_DenormPreserve : I32EnumAttrCase<"DenormPreserve", 4459> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]>, Capability<[SPV_C_DenormPreserve]> ]; } def SPV_EM_DenormFlushToZero : I32EnumAttrCase<"DenormFlushToZero", 4460> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]>, Capability<[SPV_C_DenormFlushToZero]> ]; } def SPV_EM_SignedZeroInfNanPreserve : I32EnumAttrCase<"SignedZeroInfNanPreserve", 4461> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]>, Capability<[SPV_C_SignedZeroInfNanPreserve]> ]; } def SPV_EM_RoundingModeRTE : I32EnumAttrCase<"RoundingModeRTE", 4462> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]>, Capability<[SPV_C_RoundingModeRTE]> ]; } def SPV_EM_RoundingModeRTZ : I32EnumAttrCase<"RoundingModeRTZ", 4463> { - list availability = [ + let availability = [ Extension<[SPV_KHR_float_controls]>, Capability<[SPV_C_RoundingModeRTZ]> ]; } def SPV_EM_StencilRefReplacingEXT : I32EnumAttrCase<"StencilRefReplacingEXT", 5027> { - list availability = [ + let availability = [ Extension<[SPV_EXT_shader_stencil_export]>, Capability<[SPV_C_StencilExportEXT]> ]; } def SPV_EM_OutputLinesNV : I32EnumAttrCase<"OutputLinesNV", 5269> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_EM_OutputPrimitivesNV : I32EnumAttrCase<"OutputPrimitivesNV", 5270> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_EM_DerivativeGroupQuadsNV : I32EnumAttrCase<"DerivativeGroupQuadsNV", 5289> { - list availability = [ + let availability = [ Extension<[SPV_NV_compute_shader_derivatives]>, Capability<[SPV_C_ComputeDerivativeGroupQuadsNV]> ]; } def SPV_EM_DerivativeGroupLinearNV : I32EnumAttrCase<"DerivativeGroupLinearNV", 5290> { - list availability = [ + let availability = [ Extension<[SPV_NV_compute_shader_derivatives]>, Capability<[SPV_C_ComputeDerivativeGroupLinearNV]> ]; } def SPV_EM_OutputTrianglesNV : I32EnumAttrCase<"OutputTrianglesNV", 5298> { - list availability = [ + let availability = [ Extension<[SPV_NV_mesh_shader]>, Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_EM_PixelInterlockOrderedEXT : I32EnumAttrCase<"PixelInterlockOrderedEXT", 5366> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderPixelInterlockEXT]> ]; } def SPV_EM_PixelInterlockUnorderedEXT : I32EnumAttrCase<"PixelInterlockUnorderedEXT", 5367> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderPixelInterlockEXT]> ]; } def SPV_EM_SampleInterlockOrderedEXT : I32EnumAttrCase<"SampleInterlockOrderedEXT", 5368> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderSampleInterlockEXT]> ]; } def SPV_EM_SampleInterlockUnorderedEXT : I32EnumAttrCase<"SampleInterlockUnorderedEXT", 5369> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderSampleInterlockEXT]> ]; } def SPV_EM_ShadingRateInterlockOrderedEXT : I32EnumAttrCase<"ShadingRateInterlockOrderedEXT", 5370> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderShadingRateInterlockEXT]> ]; } def SPV_EM_ShadingRateInterlockUnorderedEXT : I32EnumAttrCase<"ShadingRateInterlockUnorderedEXT", 5371> { - list availability = [ + let availability = [ Extension<[SPV_EXT_fragment_shader_interlock]>, Capability<[SPV_C_FragmentShaderShadingRateInterlockEXT]> ]; @@ -2326,77 +2299,77 @@ ]>; def SPV_EM_Vertex : I32EnumAttrCase<"Vertex", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_TessellationControl : I32EnumAttrCase<"TessellationControl", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_TessellationEvaluation : I32EnumAttrCase<"TessellationEvaluation", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Tessellation]> ]; } def SPV_EM_Geometry : I32EnumAttrCase<"Geometry", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_Geometry]> ]; } def SPV_EM_Fragment : I32EnumAttrCase<"Fragment", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_GLCompute : I32EnumAttrCase<"GLCompute", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_EM_Kernel : I32EnumAttrCase<"Kernel", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_EM_TaskNV : I32EnumAttrCase<"TaskNV", 5267> { - list availability = [ + let availability = [ Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_EM_MeshNV : I32EnumAttrCase<"MeshNV", 5268> { - list availability = [ + let availability = [ Capability<[SPV_C_MeshShadingNV]> ]; } def SPV_EM_RayGenerationNV : I32EnumAttrCase<"RayGenerationNV", 5313> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } def SPV_EM_IntersectionNV : I32EnumAttrCase<"IntersectionNV", 5314> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } def SPV_EM_AnyHitNV : I32EnumAttrCase<"AnyHitNV", 5315> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } def SPV_EM_ClosestHitNV : I32EnumAttrCase<"ClosestHitNV", 5316> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } def SPV_EM_MissNV : I32EnumAttrCase<"MissNV", 5317> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } def SPV_EM_CallableNV : I32EnumAttrCase<"CallableNV", 5318> { - list availability = [ + let availability = [ Capability<[SPV_C_RayTracingNV]> ]; } @@ -2421,40 +2394,40 @@ ]>; def SPV_GO_Reduce : I32EnumAttrCase<"Reduce", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniformArithmetic, SPV_C_GroupNonUniformBallot, SPV_C_Kernel]> ]; } def SPV_GO_InclusiveScan : I32EnumAttrCase<"InclusiveScan", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniformArithmetic, SPV_C_GroupNonUniformBallot, SPV_C_Kernel]> ]; } def SPV_GO_ExclusiveScan : I32EnumAttrCase<"ExclusiveScan", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_GroupNonUniformArithmetic, SPV_C_GroupNonUniformBallot, SPV_C_Kernel]> ]; } def SPV_GO_ClusteredReduce : I32EnumAttrCase<"ClusteredReduce", 3> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_GroupNonUniformClustered]> ]; } def SPV_GO_PartitionedReduceNV : I32EnumAttrCase<"PartitionedReduceNV", 6> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_subgroup_partitioned]>, Capability<[SPV_C_GroupNonUniformPartitionedNV]> ]; } def SPV_GO_PartitionedInclusiveScanNV : I32EnumAttrCase<"PartitionedInclusiveScanNV", 7> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_subgroup_partitioned]>, Capability<[SPV_C_GroupNonUniformPartitionedNV]> ]; } def SPV_GO_PartitionedExclusiveScanNV : I32EnumAttrCase<"PartitionedExclusiveScanNV", 8> { - list availability = [ + let availability = [ Extension<[SPV_NV_shader_subgroup_partitioned]>, Capability<[SPV_C_GroupNonUniformPartitionedNV]> ]; @@ -2469,197 +2442,197 @@ def SPV_IF_Unknown : I32EnumAttrCase<"Unknown", 0>; def SPV_IF_Rgba32f : I32EnumAttrCase<"Rgba32f", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba16f : I32EnumAttrCase<"Rgba16f", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_R32f : I32EnumAttrCase<"R32f", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba8 : I32EnumAttrCase<"Rgba8", 4> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba8Snorm : I32EnumAttrCase<"Rgba8Snorm", 5> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rg32f : I32EnumAttrCase<"Rg32f", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg16f : I32EnumAttrCase<"Rg16f", 7> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R11fG11fB10f : I32EnumAttrCase<"R11fG11fB10f", 8> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R16f : I32EnumAttrCase<"R16f", 9> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rgba16 : I32EnumAttrCase<"Rgba16", 10> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rgb10A2 : I32EnumAttrCase<"Rgb10A2", 11> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg16 : I32EnumAttrCase<"Rg16", 12> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg8 : I32EnumAttrCase<"Rg8", 13> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R16 : I32EnumAttrCase<"R16", 14> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R8 : I32EnumAttrCase<"R8", 15> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rgba16Snorm : I32EnumAttrCase<"Rgba16Snorm", 16> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg16Snorm : I32EnumAttrCase<"Rg16Snorm", 17> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg8Snorm : I32EnumAttrCase<"Rg8Snorm", 18> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R16Snorm : I32EnumAttrCase<"R16Snorm", 19> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R8Snorm : I32EnumAttrCase<"R8Snorm", 20> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rgba32i : I32EnumAttrCase<"Rgba32i", 21> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba16i : I32EnumAttrCase<"Rgba16i", 22> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba8i : I32EnumAttrCase<"Rgba8i", 23> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_R32i : I32EnumAttrCase<"R32i", 24> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rg32i : I32EnumAttrCase<"Rg32i", 25> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg16i : I32EnumAttrCase<"Rg16i", 26> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg8i : I32EnumAttrCase<"Rg8i", 27> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R16i : I32EnumAttrCase<"R16i", 28> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R8i : I32EnumAttrCase<"R8i", 29> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rgba32ui : I32EnumAttrCase<"Rgba32ui", 30> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba16ui : I32EnumAttrCase<"Rgba16ui", 31> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgba8ui : I32EnumAttrCase<"Rgba8ui", 32> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_R32ui : I32EnumAttrCase<"R32ui", 33> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_IF_Rgb10a2ui : I32EnumAttrCase<"Rgb10a2ui", 34> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg32ui : I32EnumAttrCase<"Rg32ui", 35> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg16ui : I32EnumAttrCase<"Rg16ui", 36> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_Rg8ui : I32EnumAttrCase<"Rg8ui", 37> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R16ui : I32EnumAttrCase<"R16ui", 38> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } def SPV_IF_R8ui : I32EnumAttrCase<"R8ui", 39> { - list availability = [ + let availability = [ Capability<[SPV_C_StorageImageExtendedFormats]> ]; } @@ -2678,12 +2651,12 @@ ]>; def SPV_LT_Export : I32EnumAttrCase<"Export", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Linkage]> ]; } def SPV_LT_Import : I32EnumAttrCase<"Import", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Linkage]> ]; } @@ -2697,37 +2670,37 @@ def SPV_LC_Unroll : BitEnumAttrCase<"Unroll", 0x0001>; def SPV_LC_DontUnroll : BitEnumAttrCase<"DontUnroll", 0x0002>; def SPV_LC_DependencyInfinite : BitEnumAttrCase<"DependencyInfinite", 0x0004> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_DependencyLength : BitEnumAttrCase<"DependencyLength", 0x0008> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_MinIterations : BitEnumAttrCase<"MinIterations", 0x0010> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_MaxIterations : BitEnumAttrCase<"MaxIterations", 0x0020> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_IterationMultiple : BitEnumAttrCase<"IterationMultiple", 0x0040> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_PeelCount : BitEnumAttrCase<"PeelCount", 0x0080> { - list availability = [ + let availability = [ MinVersion ]; } def SPV_LC_PartialCount : BitEnumAttrCase<"PartialCount", 0x0100> { - list availability = [ + let availability = [ MinVersion ]; } @@ -2744,19 +2717,19 @@ def SPV_MA_Aligned : BitEnumAttrCase<"Aligned", 0x0002>; def SPV_MA_Nontemporal : BitEnumAttrCase<"Nontemporal", 0x0004>; def SPV_MA_MakePointerAvailable : BitEnumAttrCase<"MakePointerAvailable", 0x0008> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; } def SPV_MA_MakePointerVisible : BitEnumAttrCase<"MakePointerVisible", 0x0010> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; } def SPV_MA_NonPrivatePointer : BitEnumAttrCase<"NonPrivatePointer", 0x0020> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; @@ -2770,22 +2743,22 @@ ]>; def SPV_MM_Simple : I32EnumAttrCase<"Simple", 0> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_MM_GLSL450 : I32EnumAttrCase<"GLSL450", 1> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_MM_OpenCL : I32EnumAttrCase<"OpenCL", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Kernel]> ]; } def SPV_MM_Vulkan : I32EnumAttrCase<"Vulkan", 3> { - list availability = [ + let availability = [ Extension<[SPV_KHR_vulkan_memory_model]>, Capability<[SPV_C_VulkanMemoryModel]> ]; @@ -2802,7 +2775,7 @@ def SPV_MS_AcquireRelease : BitEnumAttrCase<"AcquireRelease", 0x0008>; def SPV_MS_SequentiallyConsistent : BitEnumAttrCase<"SequentiallyConsistent", 0x0010>; def SPV_MS_UniformMemory : BitEnumAttrCase<"UniformMemory", 0x0040> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } @@ -2810,31 +2783,31 @@ def SPV_MS_WorkgroupMemory : BitEnumAttrCase<"WorkgroupMemory", 0x0100>; def SPV_MS_CrossWorkgroupMemory : BitEnumAttrCase<"CrossWorkgroupMemory", 0x0200>; def SPV_MS_AtomicCounterMemory : BitEnumAttrCase<"AtomicCounterMemory", 0x0400> { - list availability = [ + let availability = [ Capability<[SPV_C_AtomicStorage]> ]; } def SPV_MS_ImageMemory : BitEnumAttrCase<"ImageMemory", 0x0800>; def SPV_MS_OutputMemory : BitEnumAttrCase<"OutputMemory", 0x1000> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; } def SPV_MS_MakeAvailable : BitEnumAttrCase<"MakeAvailable", 0x2000> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; } def SPV_MS_MakeVisible : BitEnumAttrCase<"MakeVisible", 0x4000> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; } def SPV_MS_Volatile : BitEnumAttrCase<"Volatile", 0x8000> { - list availability = [ + let availability = [ Extension<[SPV_KHR_vulkan_memory_model]>, Capability<[SPV_C_VulkanMemoryModel]> ]; @@ -2855,7 +2828,7 @@ def SPV_S_Subgroup : I32EnumAttrCase<"Subgroup", 3>; def SPV_S_Invocation : I32EnumAttrCase<"Invocation", 4>; def SPV_S_QueueFamily : I32EnumAttrCase<"QueueFamily", 5> { - list availability = [ + let availability = [ MinVersion, Capability<[SPV_C_VulkanMemoryModel]> ]; @@ -2879,83 +2852,83 @@ def SPV_SC_UniformConstant : I32EnumAttrCase<"UniformConstant", 0>; def SPV_SC_Input : I32EnumAttrCase<"Input", 1>; def SPV_SC_Uniform : I32EnumAttrCase<"Uniform", 2> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_SC_Output : I32EnumAttrCase<"Output", 3> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_SC_Workgroup : I32EnumAttrCase<"Workgroup", 4>; def SPV_SC_CrossWorkgroup : I32EnumAttrCase<"CrossWorkgroup", 5>; def SPV_SC_Private : I32EnumAttrCase<"Private", 6> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_SC_Function : I32EnumAttrCase<"Function", 7>; def SPV_SC_Generic : I32EnumAttrCase<"Generic", 8> { - list availability = [ + let availability = [ Capability<[SPV_C_GenericPointer]> ]; } def SPV_SC_PushConstant : I32EnumAttrCase<"PushConstant", 9> { - list availability = [ + let availability = [ Capability<[SPV_C_Shader]> ]; } def SPV_SC_AtomicCounter : I32EnumAttrCase<"AtomicCounter", 10> { - list availability = [ + let availability = [ Capability<[SPV_C_AtomicStorage]> ]; } def SPV_SC_Image : I32EnumAttrCase<"Image", 11>; def SPV_SC_StorageBuffer : I32EnumAttrCase<"StorageBuffer", 12> { - list availability = [ + let availability = [ Extension<[SPV_KHR_storage_buffer_storage_class, SPV_KHR_variable_pointers]>, Capability<[SPV_C_Shader]> ]; } def SPV_SC_CallableDataNV : I32EnumAttrCase<"CallableDataNV", 5328> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_IncomingCallableDataNV : I32EnumAttrCase<"IncomingCallableDataNV", 5329> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_RayPayloadNV : I32EnumAttrCase<"RayPayloadNV", 5338> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_HitAttributeNV : I32EnumAttrCase<"HitAttributeNV", 5339> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_IncomingRayPayloadNV : I32EnumAttrCase<"IncomingRayPayloadNV", 5342> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_ShaderRecordBufferNV : I32EnumAttrCase<"ShaderRecordBufferNV", 5343> { - list availability = [ + let availability = [ Extension<[SPV_NV_ray_tracing]>, Capability<[SPV_C_RayTracingNV]> ]; } def SPV_SC_PhysicalStorageBuffer : I32EnumAttrCase<"PhysicalStorageBuffer", 5349> { - list availability = [ + let availability = [ Extension<[SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer]>, Capability<[SPV_C_PhysicalStorageBufferAddresses]> ]; @@ -3402,23 +3375,7 @@ // Base class for all SPIR-V ops. class SPV_Op traits = []> : - Op, - DeclareOpInterfaceMethods, - DeclareOpInterfaceMethods, - DeclareOpInterfaceMethods - ])> { - // Availability specification for this op itself. - list availability = [ - MinVersion, - MaxVersion, - Extension<[]>, - Capability<[]> - ]; - + Op { // For each SPIR-V op, the following static functions need to be defined // in SPVOps.cpp: // diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -38,6 +38,12 @@ string result = r; } +//===----------------------------------------------------------------------===// +// Forward declarations +//===----------------------------------------------------------------------===// + +class Availability; + //===----------------------------------------------------------------------===// // Predicate definitions //===----------------------------------------------------------------------===// @@ -1135,6 +1141,9 @@ // The string representation of the enumerant. May be the same as symbol. string str = strVal; + + // The list of availability classes controlling this case's availability. + list availability = ?; } // An enum attribute case stored with StringAttr. @@ -2237,6 +2246,9 @@ // Note: The list of traits will be uniqued by ODS. list traits = props; + // The list of availability classes controlling this op's availability. + list availability = ?; + // Additional code that will be added to the public part of the generated // C++ code of the op declaration. code extraClassDeclaration = ?; @@ -2281,6 +2293,89 @@ dag results = rets; } +//===----------------------------------------------------------------------===// +// Availability definitions +//===----------------------------------------------------------------------===// + +// The base class for defining op availability dimensions. +class Availability { + // The following are fields for controlling the generated C++ OpInterface. + + // The namespace for the generated C++ OpInterface subclass. + string cppNamespace = ?; + // The name for the generated C++ OpInterface subclass. + string interfaceName = ?; + // The documentation for the generated C++ OpInterface subclass. + string interfaceDescription = ""; + + // The following are fields for controlling the query function signature. + + // The query function's return type in the generated C++ OpInterface subclass. + string queryFnRetType = ?; + // The query function's name in the generated C++ OpInterface subclass. + string queryFnName = ?; + + // The following are fields for controlling the query function implementation. + + // The logic for merging two availability requirements. This is used to derive + // the final availability requirement when, for example, an op has two + // operands and these two operands have different availability requirements. + // + // The code should use `$overall` as the placeholder for the final requirement + // and `$instance` for the current availability requirement instance. + code mergeAction = ?; + // The initializer for the final availability requirement. + string initializer = ?; + // An availability instance's type. + string instanceType = ?; + + // The following are fields for a concrete availability instance. + + // The code for preparing a concrete instance. This should be C++ statements + // and will be generated before the `mergeAction` logic. + code instancePreparation = ""; + // The availability requirement carried by a concrete instance. + string instance = ?; +} + +class MinVersionBase + : Availability { + let interfaceName = name; + + let queryFnRetType = "llvm::Optional<" # scheme.returnType # ">"; + let queryFnName = "getMinVersion"; + + let mergeAction = "{ " + "if ($overall.hasValue()) { " + "$overall = static_cast<" # scheme.returnType # ">(" + "std::max(*$overall, $instance)); " + "} else { $overall = $instance; }}"; + let initializer = "::llvm::None"; + let instanceType = scheme.cppNamespace # "::" # scheme.className; + + let instance = scheme.cppNamespace # "::" # scheme.className # "::" # + min.symbol; +} + +class MaxVersionBase + : Availability { + let interfaceName = name; + + let queryFnRetType = "llvm::Optional<" # scheme.returnType # ">"; + let queryFnName = "getMaxVersion"; + + let mergeAction = "{ " + "if ($overall.hasValue()) { " + "$overall = static_cast<" # scheme.returnType # ">(" + "std::min(*$overall, $instance)); " + "} else { $overall = $instance; }}"; + let initializer = "::llvm::None"; + let instanceType = scheme.cppNamespace # "::" # scheme.className; + + let instance = scheme.cppNamespace # "::" # scheme.className # "::" # + max.symbol; +} + //===----------------------------------------------------------------------===// // Common value constraints //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/TableGen/Availability.h b/mlir/include/mlir/TableGen/Availability.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/TableGen/Availability.h @@ -0,0 +1,79 @@ +//===- Availability.h - Availability wrapper class --------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Availability wrapper to simplify using TableGen Record defining a MLIR +// Availability. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TABLEGEN_AVAILABILITY_H_ +#define MLIR_TABLEGEN_AVAILABILITY_H_ + +#include "mlir/Support/LLVM.h" + +namespace llvm { +class Record; +} // end namespace llvm + +namespace mlir { +namespace tblgen { + +// Wrapper class with helper methods for accessing availability defined in +// TableGen. +class Availability { +public: + explicit Availability(const llvm::Record *def); + + // Returns the name of the direct TableGen class for this availability + // instance. + StringRef getClass() const; + + // Returns the generated C++ interface's class namespace. + StringRef getInterfaceClassNamespace() const; + + // Returns the generated C++ interface's class name. + StringRef getInterfaceClassName() const; + + // Returns the generated C++ interface's description. + StringRef getInterfaceDescription() const; + + // Returns the name of the query function insided the generated C++ interface. + StringRef getQueryFnName() const; + + // Returns the return type of the query function insided the generated C++ + // interface. + StringRef getQueryFnRetType() const; + + // Returns the code for merging availability requirements. + StringRef getMergeActionCode() const; + + // Returns the initializer expression for initializing the final availability + // requirements. + StringRef getMergeInitializer() const; + + // Returns the C++ type for an availability instance. + StringRef getMergeInstanceType() const; + + // Returns the C++ statements for preparing availability instance. + StringRef getMergeInstancePreparation() const; + + // Returns the concrete availability instance carried in this case. + StringRef getMergeInstance() const; + + // Returns the underlying LLVM TableGen Record. + const llvm::Record *getDef() const { return def; } + +private: + // The TableGen definition of this availability. + const llvm::Record *def; +}; + +} // end namespace tblgen +} // end namespace mlir + +#endif // MLIR_TABLEGEN_AVAILABILITY_H_ diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp --- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp +++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp @@ -3777,10 +3777,3 @@ // TablenGen'erated operation definitions. #define GET_OP_CLASSES #include "mlir/Dialect/SPIRV/IR/SPIRVOps.cpp.inc" - -namespace mlir { -namespace spirv { -// TableGen'erated operation availability interface implementations. -#include "mlir/Dialect/SPIRV/IR/SPIRVOpAvailabilityImpl.inc" -} // namespace spirv -} // namespace mlir diff --git a/mlir/lib/TableGen/Availability.cpp b/mlir/lib/TableGen/Availability.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/TableGen/Availability.cpp @@ -0,0 +1,70 @@ +//===- Availability.cpp - Availability 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/TableGen/Availability.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +using namespace mlir; +using namespace mlir::tblgen; + +Availability::Availability(const llvm::Record *def) : def(def) { + assert(def->isSubClassOf("Availability") && + "must be subclass of TableGen 'Availability' class"); +} + +StringRef Availability::getClass() const { + SmallVector parentClass; + def->getDirectSuperClasses(parentClass); + if (parentClass.size() != 1) { + PrintFatalError(def->getLoc(), + "expected to only have one direct superclass"); + } + return parentClass.front()->getName(); +} + +StringRef Availability::getInterfaceClassNamespace() const { + return def->getValueAsString("cppNamespace"); +} + +StringRef Availability::getInterfaceClassName() const { + return def->getValueAsString("interfaceName"); +} + +StringRef Availability::getInterfaceDescription() const { + return def->getValueAsString("interfaceDescription"); +} + +StringRef Availability::getQueryFnRetType() const { + return def->getValueAsString("queryFnRetType"); +} + +StringRef Availability::getQueryFnName() const { + return def->getValueAsString("queryFnName"); +} + +StringRef Availability::getMergeActionCode() const { + return def->getValueAsString("mergeAction"); +} + +StringRef Availability::getMergeInitializer() const { + return def->getValueAsString("initializer"); +} + +StringRef Availability::getMergeInstanceType() const { + return def->getValueAsString("instanceType"); +} + +StringRef Availability::getMergeInstancePreparation() const { + return def->getValueAsString("instancePreparation"); +} + +StringRef Availability::getMergeInstance() const { + return def->getValueAsString("instance"); +} diff --git a/mlir/lib/TableGen/CMakeLists.txt b/mlir/lib/TableGen/CMakeLists.txt --- a/mlir/lib/TableGen/CMakeLists.txt +++ b/mlir/lib/TableGen/CMakeLists.txt @@ -12,6 +12,7 @@ Argument.cpp Attribute.cpp AttrOrTypeDef.cpp + Availability.cpp Builder.cpp Constraint.cpp Dialect.cpp diff --git a/mlir/test/Dialect/SPIRV/IR/availability.mlir b/mlir/test/Dialect/SPIRV/IR/availability.mlir --- a/mlir/test/Dialect/SPIRV/IR/availability.mlir +++ b/mlir/test/Dialect/SPIRV/IR/availability.mlir @@ -2,15 +2,15 @@ // CHECK-LABEL: iadd func @iadd(%arg: i32) -> i32 { - // CHECK: min version: v1.0 - // CHECK: max version: v1.5 - // CHECK: extensions: [ ] - // CHECK: capabilities: [ ] + // CHECK-NOT: min version + // CHECK-NOT: max version + // CHECK-NOT: extensions + // CHECK-NOT: capabilities %0 = spv.IAdd %arg, %arg: i32 return %0: i32 } -// CHECK: atomic_compare_exchange_weak +// CHECK-LABEL: atomic_compare_exchange_weak func @atomic_compare_exchange_weak(%ptr: !spv.ptr, %value: i32, %comparator: i32) -> i32 { // CHECK: min version: v1.0 // CHECK: max version: v1.3 @@ -32,8 +32,8 @@ // CHECK-LABEL: module_logical_glsl450 func @module_logical_glsl450() { - // CHECK: spv.module min version: v1.0 - // CHECK: spv.module max version: v1.5 + // CHECK-NOT: spv.module min version + // CHECK-NOT: spv.module max version // CHECK: spv.module extensions: [ ] // CHECK: spv.module capabilities: [ [Shader] ] spv.module Logical GLSL450 { } @@ -42,8 +42,8 @@ // CHECK-LABEL: module_physical_storage_buffer64_vulkan func @module_physical_storage_buffer64_vulkan() { - // CHECK: spv.module min version: v1.0 - // CHECK: spv.module max version: v1.5 + // CHECK-NOT: spv.module min version + // CHECK-NOT: spv.module max version // CHECK: spv.module extensions: [ [SPV_EXT_physical_storage_buffer, SPV_KHR_physical_storage_buffer] [SPV_KHR_vulkan_memory_model] ] // CHECK: spv.module capabilities: [ [PhysicalStorageBufferAddresses] [VulkanMemoryModel] ] spv.module PhysicalStorageBuffer64 Vulkan { } diff --git a/mlir/test/IR/op-availability.mlir b/mlir/test/IR/op-availability.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/IR/op-availability.mlir @@ -0,0 +1,78 @@ +// RUN: mlir-opt -mlir-disable-threading -test-op-availability %s | FileCheck %s + +// CHECK-LABEL: availability in @min_version +func @min_version() { + // CHECK: test.min_version_op min version: v1.1 + // CHECK: test.min_version_op has no max version requirements + "test.min_version_op"() : () -> () + return +} + +// CHECK-LABEL: availability in @max_version +func @max_version() { + // CHECK: test.max_version_op has no min version requirements + // CHECK: test.max_version_op max version: v1.2 + "test.max_version_op"() : () -> () + return +} + +// CHECK-LABEL: availability in @min_max_version +func @min_max_version() { + // CHECK: test.min_max_version_op min version: v1.0 + // CHECK: test.min_max_version_op max version: v1.3 + "test.min_max_version_op"() : () -> () + return +} + +// Enum case A (0): no version requirements +// Enum case B (1): <= v1.2 +// Enum case C (2): >= v1.1 + +// CHECK-LABEL: availability in @one_versioned_attr_op +func @one_versioned_attr_op() { + // CHECK: test.one_versioned_attr_op min version: None + // CHECK: test.one_versioned_attr_op max version: None + "test.one_versioned_attr_op"() {attr = 0: i32} : () -> () + + // CHECK: test.one_versioned_attr_op min version: None + // CHECK: test.one_versioned_attr_op max version: v1.2 + "test.one_versioned_attr_op"() {attr = 1: i32} : () -> () + + // CHECK: test.one_versioned_attr_op min version: v1.1 + // CHECK: test.one_versioned_attr_op max version: None + "test.one_versioned_attr_op"() {attr = 2: i32} : () -> () + return +} + +// CHECK-LABEL: availability in @two_versioned_attr_op +func @two_versioned_attr_op() { + // CHECK: test.two_versioned_attr_op min version: None + // CHECK: test.two_versioned_attr_op max version: v1.2 + "test.two_versioned_attr_op"() {attr1 = 0: i32, attr2 = 1: i32} : () -> () + + // CHECK: test.two_versioned_attr_op min version: v1.1 + // CHECK: test.two_versioned_attr_op max version: None + "test.two_versioned_attr_op"() {attr1 = 0: i32, attr2 = 2: i32} : () -> () + + // CHECK: test.two_versioned_attr_op min version: v1.1 + // CHECK: test.two_versioned_attr_op max version: v1.2 + "test.two_versioned_attr_op"() {attr1 = 1: i32, attr2 = 2: i32} : () -> () + return +} + + +// CHECK-LABEL: availability in @mix_versioned_attr_op +func @mix_versioned_attr_op() { + // CHECK: test.mix_versioned_attr_op min version: v1.0 + // CHECK: test.mix_versioned_attr_op max version: v1.2 + "test.mix_versioned_attr_op"() {attr1 = 0: i32, attr2 = 1: i32} : () -> () + + // CHECK: test.mix_versioned_attr_op min version: v1.1 + // CHECK: test.mix_versioned_attr_op max version: v1.3 + "test.mix_versioned_attr_op"() {attr1 = 0: i32, attr2 = 2: i32} : () -> () + + // CHECK: test.mix_versioned_attr_op min version: v1.1 + // CHECK: test.mix_versioned_attr_op max version: v1.2 + "test.mix_versioned_attr_op"() {attr1 = 1: i32, attr2 = 2: i32} : () -> () + return +} diff --git a/mlir/test/lib/Dialect/Test/CMakeLists.txt b/mlir/test/lib/Dialect/Test/CMakeLists.txt --- a/mlir/test/lib/Dialect/Test/CMakeLists.txt +++ b/mlir/test/lib/Dialect/Test/CMakeLists.txt @@ -34,6 +34,10 @@ mlir_tablegen(TestOpStructs.h.inc -gen-struct-attr-decls) mlir_tablegen(TestOpStructs.cpp.inc -gen-struct-attr-defs) mlir_tablegen(TestPatterns.inc -gen-rewriters) +mlir_tablegen(TestOpAvailability.h.inc -gen-avail-interface-decls) +mlir_tablegen(TestOpAvailability.cpp.inc -gen-avail-interface-defs) +mlir_tablegen(TestEnumAvailability.h.inc -gen-enum-avail-decls) +mlir_tablegen(TestEnumAvailability.cpp.inc -gen-enum-avail-defs) add_public_tablegen_target(MLIRTestOpsIncGen) # Exclude tests from libMLIR.so @@ -41,6 +45,7 @@ TestAttributes.cpp TestDialect.cpp TestInterfaces.cpp + TestOpAvailability.cpp TestPatterns.cpp TestTraits.cpp TestTypes.cpp diff --git a/mlir/test/lib/Dialect/Test/TestDialect.h b/mlir/test/lib/Dialect/Test/TestDialect.h --- a/mlir/test/lib/Dialect/Test/TestDialect.h +++ b/mlir/test/lib/Dialect/Test/TestDialect.h @@ -42,6 +42,11 @@ #include "TestOpStructs.h.inc" #include "TestOpsDialect.h.inc" +// This needs to be included after TestOpEnums.h.inc due to symbol dependency. +#include "TestEnumAvailability.h.inc" + +#include "TestOpAvailability.h.inc" + #define GET_OP_CLASSES #include "TestOps.h.inc" diff --git a/mlir/test/lib/Dialect/Test/TestOpAvailability.cpp b/mlir/test/lib/Dialect/Test/TestOpAvailability.cpp new file mode 100644 --- /dev/null +++ b/mlir/test/lib/Dialect/Test/TestOpAvailability.cpp @@ -0,0 +1,85 @@ +//===- TestOpAvailability.cpp - Pass to test op availability --------------===// +// +// 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 "TestDialect.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" + +using namespace mlir; + +#include "TestEnumAvailability.cpp.inc" + +namespace mlir { +namespace test { +#include "TestOpAvailability.cpp.inc" +} // namespace test +} // namespace mlir + +//===----------------------------------------------------------------------===// +// Printing op availability pass +//===----------------------------------------------------------------------===// + +namespace { +/// A pass for testing op availability. +struct PrintOpAvailability + : public PassWrapper { + StringRef getArgument() const final { return "test-op-availability"; } + StringRef getDescription() const final { return "Test op availability"; } + + void runOnFunction() override; +}; +} // end anonymous namespace + +void PrintOpAvailability::runOnFunction() { + auto f = getFunction(); + llvm::outs() << "availability in @" << f.getName() << "\n"; + + Dialect *spvDialect = getContext().getLoadedDialect("test"); + + f->walk([&](Operation *op) { + if (op->getDialect() != spvDialect) + return WalkResult::advance(); + + auto opName = op->getName(); + auto &os = llvm::outs(); + + // Check that we can access TestQueryMinVersionInterface. + if (auto minVersionIfx = dyn_cast(op)) { + auto minVersion = minVersionIfx.getMinVersion(); + os << opName << " min version: "; + if (minVersion.hasValue()) + os << stringifyVersion(minVersion.getValue()) << "\n"; + else + os << "None\n"; + } else { + os << opName << " has no min version requirements\n"; + } + + // Check that we can access TestQueryMaxVersionInterface. + if (auto maxVersionIfx = dyn_cast(op)) { + auto maxVersion = maxVersionIfx.getMaxVersion(); + os << opName << " max version: "; + if (maxVersion.hasValue()) + os << stringifyVersion(maxVersion.getValue()) << "\n"; + else + os << "None\n"; + } else { + os << opName << " has no max version requirements\n"; + } + + os.flush(); + + return WalkResult::advance(); + }); +} + +namespace mlir { +void registerPrintOpAvailabilityPass() { + PassRegistration(); +} +} // namespace mlir diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -2163,4 +2163,101 @@ def : Pat<(OpCrashLong $_, $_, $_), (OpCrashShort)>; +//===----------------------------------------------------------------------===// +// Test Op Availability +//===----------------------------------------------------------------------===// + +def Test_V_1_0 : I32EnumAttrCase<"V_1_0", 0, "v1.0">; +def Test_V_1_1 : I32EnumAttrCase<"V_1_1", 1, "v1.1">; +def Test_V_1_2 : I32EnumAttrCase<"V_1_2", 2, "v1.2">; +def Test_V_1_3 : I32EnumAttrCase<"V_1_3", 3, "v1.3">; + +def Test_VersionAttr : I32EnumAttr<"Version", "valid version numbers", [ + Test_V_1_0, Test_V_1_1, Test_V_1_2, Test_V_1_3]>; + +class Test_MinVersion : MinVersionBase< + "TestQueryMinVersionInterface", Test_VersionAttr, min> { + let interfaceDescription = [{ + Querying interface for minimal required version. + }]; + let cppNamespace = "::mlir::test"; +} + +class Test_MaxVersion : MaxVersionBase< + "TestQueryMaxVersionInterface", Test_VersionAttr, max> { + let interfaceDescription = [{ + Querying interface for maximal supported version. + }]; + let cppNamespace = "::mlir::test"; +} + +// Test op with only min version availability. +def MinVersionOp : TEST_Op<"min_version_op"> { + let arguments = (ins); + let results = (outs); + + let availability = [Test_MinVersion]; +} + +// Test op with only max version availability. +def MaxVersionOp : TEST_Op<"max_version_op"> { + let arguments = (ins); + let results = (outs); + + let availability = [Test_MaxVersion]; +} + +// Test op with both min and max version availability. +def MinMaxVersionOp : TEST_Op<"min_max_version_op"> { + let arguments = (ins); + let results = (outs); + + let availability = [ + Test_MinVersion, + Test_MaxVersion + ]; +} + +def VersionedEnumCaseA : I32EnumAttrCase<"A", 0> { + // No version requirements. +} +def VersionedEnumCaseB : I32EnumAttrCase<"B", 1> { + // Removed since v1.3. + let availability = [Test_MaxVersion]; +} +def VersionedEnumCaseC : I32EnumAttrCase<"C", 2> { + // Added since v1.1. + let availability = [Test_MinVersion]; +} + +def VersionedEnumAttr : I32EnumAttr<"VersionedEnum", "valid enum cases", [ + VersionedEnumCaseA, VersionedEnumCaseB, VersionedEnumCaseC]> { + let cppNamespace = "::mlir::test"; +} + +// Test op having one versioned enum attribute. +def OneVersionedAttrOp : TEST_Op<"one_versioned_attr_op"> { + let arguments = (ins VersionedEnumAttr:$attr); + let results = (outs); +} + +// Test op having two versioned enum attribute--the final version requirements +// need to consider both. +def TwoVersionedAttrOp : TEST_Op<"two_versioned_attr_op"> { + let arguments = (ins VersionedEnumAttr:$attr1, VersionedEnumAttr:$attr2); + let results = (outs); +} + +// Test op having availability on itself and two versioned enum attribute-- +// the final version requirements need to consider everything. +def MixVersionedAttrOp : TEST_Op<"mix_versioned_attr_op"> { + let arguments = (ins VersionedEnumAttr:$attr1, VersionedEnumAttr:$attr2); + let results = (outs); + + let availability = [ + Test_MinVersion, + Test_MaxVersion + ]; +} + #endif // TEST_OPS diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp --- a/mlir/tools/mlir-opt/mlir-opt.cpp +++ b/mlir/tools/mlir-opt/mlir-opt.cpp @@ -31,6 +31,7 @@ namespace mlir { void registerConvertToTargetEnvPass(); void registerPassManagerTestPass(); +void registerPrintOpAvailabilityPass(); void registerPrintSpirvAvailabilityPass(); void registerShapeFunctionTestPasses(); void registerSideEffectTestPasses(); @@ -112,6 +113,7 @@ void registerTestPasses() { registerConvertToTargetEnvPass(); registerPassManagerTestPass(); + registerPrintOpAvailabilityPass(); registerPrintSpirvAvailabilityPass(); registerShapeFunctionTestPasses(); registerSideEffectTestPasses(); diff --git a/mlir/tools/mlir-tblgen/AvailabilityInterfaceGen.cpp b/mlir/tools/mlir-tblgen/AvailabilityInterfaceGen.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/mlir-tblgen/AvailabilityInterfaceGen.cpp @@ -0,0 +1,177 @@ +//===- AvailabilityInterfacesGen.cpp --------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// AvailabilityInterfacesGen generates definitions for availability interfaces. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Support/LLVM.h" +#include "mlir/TableGen/Availability.h" +#include "mlir/TableGen/CodeGenHelpers.h" +#include "mlir/TableGen/GenInfo.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace mlir; +using llvm::Record; +using llvm::RecordKeeper; +using mlir::tblgen::Availability; +using mlir::tblgen::NamespaceEmitter; + +//===----------------------------------------------------------------------===// +// Availability Interface Declarations AutoGen +//===----------------------------------------------------------------------===// + +static void emitConceptDecl(const Availability &availability, raw_ostream &os) { + os << " class Concept {\n" + << " public:\n" + << " virtual ~Concept() = default;\n" + << " virtual " << availability.getQueryFnRetType() << " " + << availability.getQueryFnName() + << "(const Concept *impl, Operation *tblgen_opaque_op) const = 0;\n" + << " };\n"; +} + +static void emitModelDecl(const Availability &availability, raw_ostream &os) { + for (const char *modelClass : {"Model", "FallbackModel"}) { + os << " template\n"; + os << " class " << modelClass << " : public Concept {\n" + << " public:\n" + << " " << availability.getQueryFnRetType() << " " + << availability.getQueryFnName() + << "(const Concept *impl, Operation *tblgen_opaque_op) const final {\n" + << " auto op = llvm::cast(tblgen_opaque_op);\n" + << " (void)op;\n" + // Forward to the method on the concrete operation type. + << " return op." << availability.getQueryFnName() << "();\n" + << " }\n" + << " };\n"; + } + os << " template\n"; + os << " class ExternalModel : public FallbackModel {};\n"; +} + +static void emitInterfaceDecl(const Availability &availability, + raw_ostream &os) { + StringRef interfaceName = availability.getInterfaceClassName(); + std::string interfaceTraitsName = + std::string(formatv("{0}Traits", interfaceName)); + + StringRef cppNamespace = availability.getInterfaceClassNamespace(); + NamespaceEmitter nsEmitter(os, cppNamespace); + + // Emit the traits struct containing the concept and model declarations. + os << "namespace detail {\n" + << "struct " << interfaceTraitsName << " {\n"; + emitConceptDecl(availability, os); + os << '\n'; + emitModelDecl(availability, os); + os << "};\n} // namespace detail\n\n"; + + // Emit the main interface class declaration. + os << "/*\n" << availability.getInterfaceDescription().trim() << "\n*/\n"; + os << llvm::formatv("class {0} : public OpInterface<{1}, detail::{2}> {\n" + "public:\n" + " using OpInterface<{1}, detail::{2}>::OpInterface;\n", + interfaceName, interfaceName, interfaceTraitsName); + + // Emit query function declaration. + os << " " << availability.getQueryFnRetType() << " " + << availability.getQueryFnName() << "();\n"; + os << "};\n\n"; +} + +static bool emitInterfaceDecls(const RecordKeeper &recordKeeper, + raw_ostream &os) { + llvm::emitSourceFileHeader("Availability Interface Declarations", os); + + auto defs = recordKeeper.getAllDerivedDefinitions("Availability"); + SmallVector handledClasses; + for (const Record *def : defs) { + SmallVector parent; + def->getDirectSuperClasses(parent); + if (parent.size() != 1) { + PrintFatalError(def->getLoc(), + "expected to only have one direct superclass"); + } + if (llvm::is_contained(handledClasses, parent.front())) + continue; + + Availability avail(def); + emitInterfaceDecl(avail, os); + handledClasses.push_back(parent.front()); + } + return false; +} + +//===----------------------------------------------------------------------===// +// Availability Interface Definitions AutoGen +//===----------------------------------------------------------------------===// + +static void emitInterfaceDef(const Availability &availability, + raw_ostream &os) { + os << availability.getQueryFnRetType() << " "; + + StringRef cppNamespace = availability.getInterfaceClassNamespace(); + cppNamespace.consume_front("::"); + if (!cppNamespace.empty()) + os << cppNamespace << "::"; + + StringRef methodName = availability.getQueryFnName(); + os << availability.getInterfaceClassName() << "::" << methodName << "() {\n" + << " return getImpl()->" << methodName << "(getImpl(), getOperation());\n" + << "}\n"; +} + +static bool emitInterfaceDefs(const RecordKeeper &recordKeeper, + raw_ostream &os) { + llvm::emitSourceFileHeader("Availability Interface Definitions", os); + + auto defs = recordKeeper.getAllDerivedDefinitions("Availability"); + SmallVector handledClasses; + for (const Record *def : defs) { + SmallVector parent; + def->getDirectSuperClasses(parent); + if (parent.size() != 1) { + PrintFatalError(def->getLoc(), + "expected to only have one direct superclass"); + } + if (llvm::is_contained(handledClasses, parent.front())) + continue; + + Availability availability(def); + emitInterfaceDef(availability, os); + handledClasses.push_back(parent.front()); + } + return false; +} + +//===----------------------------------------------------------------------===// +// Availability Interface Hook Registration +//===----------------------------------------------------------------------===// + +// Registers the operation interface generator to mlir-tblgen. +static mlir::GenRegistration + genInterfaceDecls("gen-avail-interface-decls", + "Generate availability interface declarations", + [](const RecordKeeper &records, raw_ostream &os) { + return emitInterfaceDecls(records, os); + }); + +// Registers the operation interface generator to mlir-tblgen. +static mlir::GenRegistration + genInterfaceDefs("gen-avail-interface-defs", + "Generate op interface definitions", + [](const RecordKeeper &records, raw_ostream &os) { + return emitInterfaceDefs(records, os); + }); diff --git a/mlir/tools/mlir-tblgen/CMakeLists.txt b/mlir/tools/mlir-tblgen/CMakeLists.txt --- a/mlir/tools/mlir-tblgen/CMakeLists.txt +++ b/mlir/tools/mlir-tblgen/CMakeLists.txt @@ -6,6 +6,7 @@ add_tablegen(mlir-tblgen MLIR AttrOrTypeDefGen.cpp + AvailabilityInterfaceGen.cpp DialectGen.cpp DirectiveCommonGen.cpp EnumsGen.cpp diff --git a/mlir/tools/mlir-tblgen/EnumsGen.cpp b/mlir/tools/mlir-tblgen/EnumsGen.cpp --- a/mlir/tools/mlir-tblgen/EnumsGen.cpp +++ b/mlir/tools/mlir-tblgen/EnumsGen.cpp @@ -11,10 +11,12 @@ //===----------------------------------------------------------------------===// #include "mlir/TableGen/Attribute.h" +#include "mlir/TableGen/Availability.h" #include "mlir/TableGen/Format.h" #include "mlir/TableGen/GenInfo.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -29,6 +31,7 @@ using llvm::RecordKeeper; using llvm::StringRef; using mlir::tblgen::Attribute; +using mlir::tblgen::Availability; using mlir::tblgen::EnumAttr; using mlir::tblgen::EnumAttrCase; using mlir::tblgen::FmtContext; @@ -42,6 +45,10 @@ return str.str(); } +//===----------------------------------------------------------------------===// +// Enum Utility AutoGen +//===----------------------------------------------------------------------===// + static void emitEnumClass(const Record &enumDef, StringRef enumName, StringRef underlyingType, StringRef description, const std::vector &enumerants, @@ -540,6 +547,10 @@ return false; } +//===----------------------------------------------------------------------===// +// Enum Utility Query Hook Registration +//===----------------------------------------------------------------------===// + // Registers the enum utility generator to mlir-tblgen. static mlir::GenRegistration genEnumDecls("gen-enum-decls", "Generate enum utility declarations", @@ -553,3 +564,202 @@ [](const RecordKeeper &records, raw_ostream &os) { return emitEnumDefs(records, os); }); + +//===----------------------------------------------------------------------===// +// Enum Availability Query AutoGen +//===----------------------------------------------------------------------===// + +// Returns the availability spec of the given `def`. +static std::vector getAvailabilities(const llvm::Record &def) { + std::vector availabilities; + + if (def.getValue("availability") && !def.isValueUnset("availability")) { + std::vector availDefs = + def.getValueAsListOfDefs("availability"); + availabilities.reserve(availDefs.size()); + for (const llvm::Record *avail : availDefs) + availabilities.emplace_back(avail); + } + + return availabilities; +} + +static void emitAvailabilityQueryForIntEnum(const Record &enumDef, + raw_ostream &os) { + EnumAttr enumAttr(enumDef); + StringRef enumName = enumAttr.getEnumClassName(); + std::vector enumerants = enumAttr.getAllCases(); + + // Mapping from availability class name to (enumerant, availability + // specification) pairs. + llvm::StringMap, 1>> + classCaseMap; + + // Place all availability specifications to their corresponding + // availability classes. + for (const EnumAttrCase &enumerant : enumerants) + for (const Availability &avail : getAvailabilities(enumerant.getDef())) + classCaseMap[avail.getClass()].push_back({enumerant, avail}); + + for (const auto &classCasePair : classCaseMap) { + Availability avail = classCasePair.getValue().front().second; + + os << formatv("llvm::Optional<{0}> {1}({2} value) {{\n", + avail.getMergeInstanceType(), avail.getQueryFnName(), + enumName); + + os << " switch (value) {\n"; + for (const auto &caseSpecPair : classCasePair.getValue()) { + EnumAttrCase enumerant = caseSpecPair.first; + Availability avail = caseSpecPair.second; + os << formatv(" case {0}::{1}: { {2} return {3}({4}); }\n", enumName, + enumerant.getSymbol(), avail.getMergeInstancePreparation(), + avail.getMergeInstanceType(), avail.getMergeInstance()); + } + // Only emit default if uncovered cases. + if (classCasePair.getValue().size() < enumAttr.getAllCases().size()) + os << " default: break;\n"; + os << " }\n" + << " return llvm::None;\n" + << "}\n"; + } +} + +static void emitAvailabilityQueryForBitEnum(const Record &enumDef, + raw_ostream &os) { + EnumAttr enumAttr(enumDef); + StringRef enumName = enumAttr.getEnumClassName(); + std::string underlyingType = std::string(enumAttr.getUnderlyingType()); + std::vector enumerants = enumAttr.getAllCases(); + + // Mapping from availability class name to (enumerant, availability + // specification) pairs. + llvm::StringMap, 1>> + classCaseMap; + + // Place all availability specifications to their corresponding + // availability classes. + for (const EnumAttrCase &enumerant : enumerants) + for (const Availability &avail : getAvailabilities(enumerant.getDef())) + classCaseMap[avail.getClass()].push_back({enumerant, avail}); + + for (const auto &classCasePair : classCaseMap) { + Availability avail = classCasePair.getValue().front().second; + + os << formatv("llvm::Optional<{0}> {1}({2} value) {{\n", + avail.getMergeInstanceType(), avail.getQueryFnName(), + enumName); + + os << formatv( + " assert(::llvm::countPopulation(static_cast<{0}>(value)) <= 1" + " && \"cannot have more than one bit set\");\n", + underlyingType); + + os << " switch (value) {\n"; + for (const auto &caseSpecPair : classCasePair.getValue()) { + EnumAttrCase enumerant = caseSpecPair.first; + Availability avail = caseSpecPair.second; + os << formatv(" case {0}::{1}: { {2} return {3}({4}); }\n", enumName, + enumerant.getSymbol(), avail.getMergeInstancePreparation(), + avail.getMergeInstanceType(), avail.getMergeInstance()); + } + os << " default: break;\n"; + os << " }\n" + << " return llvm::None;\n" + << "}\n"; + } +} + +static void emitEnumAvailDecl(const Record &enumDef, raw_ostream &os) { + EnumAttr enumAttr(enumDef); + StringRef enumName = enumAttr.getEnumClassName(); + StringRef cppNamespace = enumAttr.getCppNamespace(); + auto enumerants = enumAttr.getAllCases(); + + llvm::SmallVector namespaces; + llvm::SplitString(cppNamespace, namespaces, "::"); + + for (auto ns : namespaces) + os << "namespace " << ns << " {\n"; + + llvm::StringSet<> handledClasses; + + // Place all availability specifications to their corresponding + // availability classes. + for (const EnumAttrCase &enumerant : enumerants) + for (const Availability &avail : getAvailabilities(enumerant.getDef())) { + StringRef className = avail.getClass(); + if (handledClasses.count(className)) + continue; + os << formatv("llvm::Optional<{0}> {1}({2} value);\n", + avail.getMergeInstanceType(), avail.getQueryFnName(), + enumName); + handledClasses.insert(className); + } + + for (auto ns : llvm::reverse(namespaces)) + os << "} // namespace " << ns << "\n"; +} + +static bool emitEnumAvailDecls(const RecordKeeper &recordKeeper, + raw_ostream &os) { + llvm::emitSourceFileHeader("Enum Availability Declarations", os); + + auto defs = recordKeeper.getAllDerivedDefinitions("EnumAttrInfo"); + for (const auto *def : defs) + emitEnumAvailDecl(*def, os); + + return false; +} + +static void emitEnumAvailDef(const Record &enumDef, raw_ostream &os) { + EnumAttr enumAttr(enumDef); + StringRef cppNamespace = enumAttr.getCppNamespace(); + + llvm::SmallVector namespaces; + llvm::SplitString(cppNamespace, namespaces, "::"); + + for (auto ns : namespaces) + os << "namespace " << ns << " {\n"; + + if (enumAttr.isBitEnum()) { + emitAvailabilityQueryForBitEnum(enumDef, os); + } else { + emitAvailabilityQueryForIntEnum(enumDef, os); + } + + for (auto ns : llvm::reverse(namespaces)) + os << "} // namespace " << ns << "\n"; + os << "\n"; +} + +static bool emitEnumAvailDefs(const RecordKeeper &recordKeeper, + raw_ostream &os) { + llvm::emitSourceFileHeader("Enum Availability Definitions", os); + + auto defs = recordKeeper.getAllDerivedDefinitions("EnumAttrInfo"); + for (const auto *def : defs) + emitEnumAvailDef(*def, os); + + return false; +} + +//===----------------------------------------------------------------------===// +// Enum Availability Query Hook Registration +//===----------------------------------------------------------------------===// + +// Registers the enum utility generator to mlir-tblgen. +static mlir::GenRegistration + genEnumAvailDecls("gen-enum-avail-decls", + "Generate enum availability declarations", + [](const RecordKeeper &records, raw_ostream &os) { + return emitEnumAvailDecls(records, os); + }); + +// Registers the enum utility generator to mlir-tblgen. +static mlir::GenRegistration + genEnumAvailDefs("gen-enum-avail-defs", + "Generate enum availability definitions", + [](const RecordKeeper &records, raw_ostream &os) { + return emitEnumAvailDefs(records, os); + }); diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp --- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp @@ -13,6 +13,7 @@ #include "OpFormatGen.h" #include "OpGenHelpers.h" +#include "mlir/TableGen/Availability.h" #include "mlir/TableGen/CodeGenHelpers.h" #include "mlir/TableGen/Format.h" #include "mlir/TableGen/GenInfo.h" @@ -478,6 +479,9 @@ // Generate the type inference interface methods. void genTypeInterfaceMethods(); + // Generate availability interface methods. + void genAvailabilityInterfaceMethods(); + private: // The TableGen record for this op. // TODO: OpEmitter should not have a Record directly, @@ -641,6 +645,7 @@ genVerifier(); genCanonicalizerDecls(); genFolderDecls(); + genAvailabilityInterfaceMethods(); genTypeInterfaceMethods(); genOpInterfaceMethods(); generateOpFormat(op, opClass); @@ -1987,6 +1992,133 @@ } } +// Returns the availability spec of the given `def`. +static std::vector getAvailabilities(const llvm::Record &def) { + std::vector availabilities; + + if (def.getValue("availability") && !def.isValueUnset("availability")) { + std::vector availDefs = + def.getValueAsListOfDefs("availability"); + availabilities.reserve(availDefs.size()); + for (const llvm::Record *avail : availDefs) + availabilities.emplace_back(avail); + } + + return availabilities; +} + +void OpEmitter::genAvailabilityInterfaceMethods() { + mlir::tblgen::FmtContext fctx; + fctx.addSubst("overall", "tblgen_overall"); + + std::vector opAvailabilities = getAvailabilities(op.getDef()); + + // First collect all availability classes this op should implement. + // All availability instances keep information for the generated interface and + // the instance's specific requirement. Here we remember a random instance so + // we can get the information regarding the generated interface. + llvm::StringMap availClasses; + for (const Availability &avail : opAvailabilities) + availClasses.try_emplace(avail.getClass(), avail); + for (const NamedAttribute &namedAttr : op.getAttributes()) { + const auto *enumAttr = llvm::dyn_cast(&namedAttr.attr); + if (!enumAttr) + continue; + + for (const EnumAttrCase &enumerant : enumAttr->getAllCases()) + for (const Availability &caseAvail : + getAvailabilities(enumerant.getDef())) + availClasses.try_emplace(caseAvail.getClass(), caseAvail); + } + + // Then generate implementation for each availability class. + for (const auto &availClass : availClasses) { + StringRef availClassName = availClass.getKey(); + Availability avail = availClass.getValue(); + + auto *method = opClass.addMethodAndPrune(avail.getQueryFnRetType(), + avail.getQueryFnName()); + assert(method && "method already registered!"); + auto &body = method->body(); + + // Create the variable for the final requirement and initialize it. + body << formatv(" {0} tblgen_overall = {1};\n", avail.getQueryFnRetType(), + avail.getMergeInitializer()); + + // Update with the op's specific availability spec. + for (const Availability &avail : opAvailabilities) { + if (avail.getClass() == availClassName && + (!avail.getMergeInstancePreparation().empty() || + !avail.getMergeActionCode().empty())) { + body << " {\n " + // Prepare this instance. + << avail.getMergeInstancePreparation() + << "\n " + // Merge this instance. + << std::string( + tgfmt(avail.getMergeActionCode(), + &fctx.addSubst("instance", avail.getMergeInstance()))) + << ";\n }\n"; + } + } + + // Update with enum attributes' specific availability spec. + for (const NamedAttribute &namedAttr : op.getAttributes()) { + const auto *enumAttr = llvm::dyn_cast(&namedAttr.attr); + if (!enumAttr) + continue; + + // (enumerant, availability specification) pairs for this availability + // class. + SmallVector, 1> caseSpecs; + + // Collect all cases' availability specs. + for (const EnumAttrCase &enumerant : enumAttr->getAllCases()) + for (const Availability &caseAvail : + getAvailabilities(enumerant.getDef())) + if (availClassName == caseAvail.getClass()) + caseSpecs.push_back({enumerant, caseAvail}); + + // If this attribute kind does not have any availability spec from any of + // its cases, no more work to do. + if (caseSpecs.empty()) + continue; + + if (enumAttr->isBitEnum()) { + // For BitEnumAttr, we need to iterate over each bit to query its + // availability spec. + body << formatv(" for (unsigned i = 0; " + "i < std::numeric_limits<{0}>::digits; ++i) {{\n", + enumAttr->getUnderlyingType()); + body << formatv(" {0}::{1} tblgen_attrVal = this->{2}() & " + "static_cast<{0}::{1}>(1 << i);\n", + enumAttr->getCppNamespace(), + enumAttr->getEnumClassName(), namedAttr.name); + body << formatv( + " if (static_cast<{0}>(tblgen_attrVal) == 0) continue;\n", + enumAttr->getUnderlyingType()); + } else { + // For IntEnumAttr, we just need to query the value as a whole. + body << " {\n"; + body << formatv(" auto tblgen_attrVal = this->{0}();\n", + namedAttr.name); + } + body << formatv(" auto tblgen_instance = {0}::{1}(tblgen_attrVal);\n", + enumAttr->getCppNamespace(), avail.getQueryFnName()); + body << " if (tblgen_instance) " + // TODO` here once ODS supports + // dialect-specific contents so that we can use not implementing the + // availability interface as indication of no requirements. + << std::string(tgfmt(caseSpecs.front().second.getMergeActionCode(), + &fctx.addSubst("instance", "*tblgen_instance"))) + << ";\n"; + body << " }\n"; + } + + body << " return tblgen_overall;\n"; + } +} + void OpEmitter::genTypeInterfaceMethods() { if (!op.allResultTypesKnown()) return; @@ -2313,11 +2445,37 @@ // Add the native and interface traits. for (const auto &trait : op.getTraits()) { - if (auto opTrait = dyn_cast(&trait)) + if (const auto *opTrait = dyn_cast(&trait)) opClass.addTrait(opTrait->getFullyQualifiedTraitName()); - else if (auto opTrait = dyn_cast(&trait)) + else if (const auto *opTrait = dyn_cast(&trait)) opClass.addTrait(opTrait->getFullyQualifiedTraitName()); } + + // Add availability interfact traits. + llvm::DenseSet availClasses; + + // Add availability requirements from the op itself. + for (const Availability &avail : getAvailabilities(op.getDef())) + availClasses.insert(avail.getDef()); + + // Add availability requirements from its attributes. + for (const NamedAttribute &namedAttr : op.getAttributes()) { + const auto *enumAttr = llvm::dyn_cast(&namedAttr.attr); + if (!enumAttr) + continue; + + for (const EnumAttrCase &enumerant : enumAttr->getAllCases()) + for (const Availability &caseAvail : + getAvailabilities(enumerant.getDef())) + availClasses.insert(caseAvail.getDef()); + } + + for (const auto *a : availClasses) { + Availability avail(a); + opClass.addTrait(formatv("{0}::{1}::Trait", + avail.getInterfaceClassNamespace(), + avail.getInterfaceClassName())); + } } void OpEmitter::genOpNameGetter() { diff --git a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp --- a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp +++ b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp @@ -36,7 +36,6 @@ using llvm::raw_string_ostream; using llvm::Record; using llvm::RecordKeeper; -using llvm::SmallVector; using llvm::SMLoc; using llvm::StringMap; using llvm::StringRef; @@ -46,465 +45,8 @@ using mlir::tblgen::EnumAttrCase; using mlir::tblgen::NamedAttribute; using mlir::tblgen::NamedTypeConstraint; -using mlir::tblgen::NamespaceEmitter; using mlir::tblgen::Operator; -//===----------------------------------------------------------------------===// -// Availability Wrapper Class -//===----------------------------------------------------------------------===// - -namespace { -// Wrapper class with helper methods for accessing availability defined in -// TableGen. -class Availability { -public: - explicit Availability(const Record *def); - - // Returns the name of the direct TableGen class for this availability - // instance. - StringRef getClass() const; - - // Returns the generated C++ interface's class namespace. - StringRef getInterfaceClassNamespace() const; - - // Returns the generated C++ interface's class name. - StringRef getInterfaceClassName() const; - - // Returns the generated C++ interface's description. - StringRef getInterfaceDescription() const; - - // Returns the name of the query function insided the generated C++ interface. - StringRef getQueryFnName() const; - - // Returns the return type of the query function insided the generated C++ - // interface. - StringRef getQueryFnRetType() const; - - // Returns the code for merging availability requirements. - StringRef getMergeActionCode() const; - - // Returns the initializer expression for initializing the final availability - // requirements. - StringRef getMergeInitializer() const; - - // Returns the C++ type for an availability instance. - StringRef getMergeInstanceType() const; - - // Returns the C++ statements for preparing availability instance. - StringRef getMergeInstancePreparation() const; - - // Returns the concrete availability instance carried in this case. - StringRef getMergeInstance() const; - - // Returns the underlying LLVM TableGen Record. - const llvm::Record *getDef() const { return def; } - -private: - // The TableGen definition of this availability. - const llvm::Record *def; -}; -} // namespace - -Availability::Availability(const llvm::Record *def) : def(def) { - assert(def->isSubClassOf("Availability") && - "must be subclass of TableGen 'Availability' class"); -} - -StringRef Availability::getClass() const { - SmallVector parentClass; - def->getDirectSuperClasses(parentClass); - if (parentClass.size() != 1) { - PrintFatalError(def->getLoc(), - "expected to only have one direct superclass"); - } - return parentClass.front()->getName(); -} - -StringRef Availability::getInterfaceClassNamespace() const { - return def->getValueAsString("cppNamespace"); -} - -StringRef Availability::getInterfaceClassName() const { - return def->getValueAsString("interfaceName"); -} - -StringRef Availability::getInterfaceDescription() const { - return def->getValueAsString("interfaceDescription"); -} - -StringRef Availability::getQueryFnRetType() const { - return def->getValueAsString("queryFnRetType"); -} - -StringRef Availability::getQueryFnName() const { - return def->getValueAsString("queryFnName"); -} - -StringRef Availability::getMergeActionCode() const { - return def->getValueAsString("mergeAction"); -} - -StringRef Availability::getMergeInitializer() const { - return def->getValueAsString("initializer"); -} - -StringRef Availability::getMergeInstanceType() const { - return def->getValueAsString("instanceType"); -} - -StringRef Availability::getMergeInstancePreparation() const { - return def->getValueAsString("instancePreparation"); -} - -StringRef Availability::getMergeInstance() const { - return def->getValueAsString("instance"); -} - -// Returns the availability spec of the given `def`. -std::vector getAvailabilities(const Record &def) { - std::vector availabilities; - - if (def.getValue("availability")) { - std::vector availDefs = def.getValueAsListOfDefs("availability"); - availabilities.reserve(availDefs.size()); - for (const Record *avail : availDefs) - availabilities.emplace_back(avail); - } - - return availabilities; -} - -//===----------------------------------------------------------------------===// -// Availability Interface Definitions AutoGen -//===----------------------------------------------------------------------===// - -static void emitInterfaceDef(const Availability &availability, - raw_ostream &os) { - - os << availability.getQueryFnRetType() << " "; - - StringRef cppNamespace = availability.getInterfaceClassNamespace(); - cppNamespace.consume_front("::"); - if (!cppNamespace.empty()) - os << cppNamespace << "::"; - - StringRef methodName = availability.getQueryFnName(); - os << availability.getInterfaceClassName() << "::" << methodName << "() {\n" - << " return getImpl()->" << methodName << "(getImpl(), getOperation());\n" - << "}\n"; -} - -static bool emitInterfaceDefs(const RecordKeeper &recordKeeper, - raw_ostream &os) { - llvm::emitSourceFileHeader("Availability Interface Definitions", os); - - auto defs = recordKeeper.getAllDerivedDefinitions("Availability"); - SmallVector handledClasses; - for (const Record *def : defs) { - SmallVector parent; - def->getDirectSuperClasses(parent); - if (parent.size() != 1) { - PrintFatalError(def->getLoc(), - "expected to only have one direct superclass"); - } - if (llvm::is_contained(handledClasses, parent.front())) - continue; - - Availability availability(def); - emitInterfaceDef(availability, os); - handledClasses.push_back(parent.front()); - } - return false; -} - -//===----------------------------------------------------------------------===// -// Availability Interface Declarations AutoGen -//===----------------------------------------------------------------------===// - -static void emitConceptDecl(const Availability &availability, raw_ostream &os) { - os << " class Concept {\n" - << " public:\n" - << " virtual ~Concept() = default;\n" - << " virtual " << availability.getQueryFnRetType() << " " - << availability.getQueryFnName() - << "(const Concept *impl, Operation *tblgen_opaque_op) const = 0;\n" - << " };\n"; -} - -static void emitModelDecl(const Availability &availability, raw_ostream &os) { - for (const char *modelClass : {"Model", "FallbackModel"}) { - os << " template\n"; - os << " class " << modelClass << " : public Concept {\n" - << " public:\n" - << " " << availability.getQueryFnRetType() << " " - << availability.getQueryFnName() - << "(const Concept *impl, Operation *tblgen_opaque_op) const final {\n" - << " auto op = llvm::cast(tblgen_opaque_op);\n" - << " (void)op;\n" - // Forward to the method on the concrete operation type. - << " return op." << availability.getQueryFnName() << "();\n" - << " }\n" - << " };\n"; - } - os << " template\n"; - os << " class ExternalModel : public FallbackModel {};\n"; -} - -static void emitInterfaceDecl(const Availability &availability, - raw_ostream &os) { - StringRef interfaceName = availability.getInterfaceClassName(); - std::string interfaceTraitsName = - std::string(formatv("{0}Traits", interfaceName)); - - StringRef cppNamespace = availability.getInterfaceClassNamespace(); - NamespaceEmitter nsEmitter(os, cppNamespace); - - // Emit the traits struct containing the concept and model declarations. - os << "namespace detail {\n" - << "struct " << interfaceTraitsName << " {\n"; - emitConceptDecl(availability, os); - os << '\n'; - emitModelDecl(availability, os); - os << "};\n} // namespace detail\n\n"; - - // Emit the main interface class declaration. - os << "/*\n" << availability.getInterfaceDescription().trim() << "\n*/\n"; - os << llvm::formatv("class {0} : public OpInterface<{1}, detail::{2}> {\n" - "public:\n" - " using OpInterface<{1}, detail::{2}>::OpInterface;\n", - interfaceName, interfaceName, interfaceTraitsName); - - // Emit query function declaration. - os << " " << availability.getQueryFnRetType() << " " - << availability.getQueryFnName() << "();\n"; - os << "};\n\n"; -} - -static bool emitInterfaceDecls(const RecordKeeper &recordKeeper, - raw_ostream &os) { - llvm::emitSourceFileHeader("Availability Interface Declarations", os); - - auto defs = recordKeeper.getAllDerivedDefinitions("Availability"); - SmallVector handledClasses; - for (const Record *def : defs) { - SmallVector parent; - def->getDirectSuperClasses(parent); - if (parent.size() != 1) { - PrintFatalError(def->getLoc(), - "expected to only have one direct superclass"); - } - if (llvm::is_contained(handledClasses, parent.front())) - continue; - - Availability avail(def); - emitInterfaceDecl(avail, os); - handledClasses.push_back(parent.front()); - } - return false; -} - -//===----------------------------------------------------------------------===// -// Availability Interface Hook Registration -//===----------------------------------------------------------------------===// - -// Registers the operation interface generator to mlir-tblgen. -static mlir::GenRegistration - genInterfaceDecls("gen-avail-interface-decls", - "Generate availability interface declarations", - [](const RecordKeeper &records, raw_ostream &os) { - return emitInterfaceDecls(records, os); - }); - -// Registers the operation interface generator to mlir-tblgen. -static mlir::GenRegistration - genInterfaceDefs("gen-avail-interface-defs", - "Generate op interface definitions", - [](const RecordKeeper &records, raw_ostream &os) { - return emitInterfaceDefs(records, os); - }); - -//===----------------------------------------------------------------------===// -// Enum Availability Query AutoGen -//===----------------------------------------------------------------------===// - -static void emitAvailabilityQueryForIntEnum(const Record &enumDef, - raw_ostream &os) { - EnumAttr enumAttr(enumDef); - StringRef enumName = enumAttr.getEnumClassName(); - std::vector enumerants = enumAttr.getAllCases(); - - // Mapping from availability class name to (enumerant, availability - // specification) pairs. - llvm::StringMap, 1>> - classCaseMap; - - // Place all availability specifications to their corresponding - // availability classes. - for (const EnumAttrCase &enumerant : enumerants) - for (const Availability &avail : getAvailabilities(enumerant.getDef())) - classCaseMap[avail.getClass()].push_back({enumerant, avail}); - - for (const auto &classCasePair : classCaseMap) { - Availability avail = classCasePair.getValue().front().second; - - os << formatv("llvm::Optional<{0}> {1}({2} value) {{\n", - avail.getMergeInstanceType(), avail.getQueryFnName(), - enumName); - - os << " switch (value) {\n"; - for (const auto &caseSpecPair : classCasePair.getValue()) { - EnumAttrCase enumerant = caseSpecPair.first; - Availability avail = caseSpecPair.second; - os << formatv(" case {0}::{1}: { {2} return {3}({4}); }\n", enumName, - enumerant.getSymbol(), avail.getMergeInstancePreparation(), - avail.getMergeInstanceType(), avail.getMergeInstance()); - } - // Only emit default if uncovered cases. - if (classCasePair.getValue().size() < enumAttr.getAllCases().size()) - os << " default: break;\n"; - os << " }\n" - << " return llvm::None;\n" - << "}\n"; - } -} - -static void emitAvailabilityQueryForBitEnum(const Record &enumDef, - raw_ostream &os) { - EnumAttr enumAttr(enumDef); - StringRef enumName = enumAttr.getEnumClassName(); - std::string underlyingType = std::string(enumAttr.getUnderlyingType()); - std::vector enumerants = enumAttr.getAllCases(); - - // Mapping from availability class name to (enumerant, availability - // specification) pairs. - llvm::StringMap, 1>> - classCaseMap; - - // Place all availability specifications to their corresponding - // availability classes. - for (const EnumAttrCase &enumerant : enumerants) - for (const Availability &avail : getAvailabilities(enumerant.getDef())) - classCaseMap[avail.getClass()].push_back({enumerant, avail}); - - for (const auto &classCasePair : classCaseMap) { - Availability avail = classCasePair.getValue().front().second; - - os << formatv("llvm::Optional<{0}> {1}({2} value) {{\n", - avail.getMergeInstanceType(), avail.getQueryFnName(), - enumName); - - os << formatv( - " assert(::llvm::countPopulation(static_cast<{0}>(value)) <= 1" - " && \"cannot have more than one bit set\");\n", - underlyingType); - - os << " switch (value) {\n"; - for (const auto &caseSpecPair : classCasePair.getValue()) { - EnumAttrCase enumerant = caseSpecPair.first; - Availability avail = caseSpecPair.second; - os << formatv(" case {0}::{1}: { {2} return {3}({4}); }\n", enumName, - enumerant.getSymbol(), avail.getMergeInstancePreparation(), - avail.getMergeInstanceType(), avail.getMergeInstance()); - } - os << " default: break;\n"; - os << " }\n" - << " return llvm::None;\n" - << "}\n"; - } -} - -static void emitEnumDecl(const Record &enumDef, raw_ostream &os) { - EnumAttr enumAttr(enumDef); - StringRef enumName = enumAttr.getEnumClassName(); - StringRef cppNamespace = enumAttr.getCppNamespace(); - auto enumerants = enumAttr.getAllCases(); - - llvm::SmallVector namespaces; - llvm::SplitString(cppNamespace, namespaces, "::"); - - for (auto ns : namespaces) - os << "namespace " << ns << " {\n"; - - llvm::StringSet<> handledClasses; - - // Place all availability specifications to their corresponding - // availability classes. - for (const EnumAttrCase &enumerant : enumerants) - for (const Availability &avail : getAvailabilities(enumerant.getDef())) { - StringRef className = avail.getClass(); - if (handledClasses.count(className)) - continue; - os << formatv("llvm::Optional<{0}> {1}({2} value);\n", - avail.getMergeInstanceType(), avail.getQueryFnName(), - enumName); - handledClasses.insert(className); - } - - for (auto ns : llvm::reverse(namespaces)) - os << "} // namespace " << ns << "\n"; -} - -static bool emitEnumDecls(const RecordKeeper &recordKeeper, raw_ostream &os) { - llvm::emitSourceFileHeader("SPIR-V Enum Availability Declarations", os); - - auto defs = recordKeeper.getAllDerivedDefinitions("EnumAttrInfo"); - for (const auto *def : defs) - emitEnumDecl(*def, os); - - return false; -} - -static void emitEnumDef(const Record &enumDef, raw_ostream &os) { - EnumAttr enumAttr(enumDef); - StringRef cppNamespace = enumAttr.getCppNamespace(); - - llvm::SmallVector namespaces; - llvm::SplitString(cppNamespace, namespaces, "::"); - - for (auto ns : namespaces) - os << "namespace " << ns << " {\n"; - - if (enumAttr.isBitEnum()) { - emitAvailabilityQueryForBitEnum(enumDef, os); - } else { - emitAvailabilityQueryForIntEnum(enumDef, os); - } - - for (auto ns : llvm::reverse(namespaces)) - os << "} // namespace " << ns << "\n"; - os << "\n"; -} - -static bool emitEnumDefs(const RecordKeeper &recordKeeper, raw_ostream &os) { - llvm::emitSourceFileHeader("SPIR-V Enum Availability Definitions", os); - - auto defs = recordKeeper.getAllDerivedDefinitions("EnumAttrInfo"); - for (const auto *def : defs) - emitEnumDef(*def, os); - - return false; -} - -//===----------------------------------------------------------------------===// -// Enum Availability Query Hook Registration -//===----------------------------------------------------------------------===// - -// Registers the enum utility generator to mlir-tblgen. -static mlir::GenRegistration - genEnumDecls("gen-spirv-enum-avail-decls", - "Generate SPIR-V enum availability declarations", - [](const RecordKeeper &records, raw_ostream &os) { - return emitEnumDecls(records, os); - }); - -// Registers the enum utility generator to mlir-tblgen. -static mlir::GenRegistration - genEnumDefs("gen-spirv-enum-avail-defs", - "Generate SPIR-V enum availability definitions", - [](const RecordKeeper &records, raw_ostream &os) { - return emitEnumDefs(records, os); - }); - //===----------------------------------------------------------------------===// // Serialization AutoGen //===----------------------------------------------------------------------===// @@ -1240,145 +782,6 @@ return emitAttrUtils(records, os); }); -//===----------------------------------------------------------------------===// -// SPIR-V Availability Impl AutoGen -//===----------------------------------------------------------------------===// - -static void emitAvailabilityImpl(const Operator &srcOp, raw_ostream &os) { - mlir::tblgen::FmtContext fctx; - fctx.addSubst("overall", "tblgen_overall"); - - std::vector opAvailabilities = - getAvailabilities(srcOp.getDef()); - - // First collect all availability classes this op should implement. - // All availability instances keep information for the generated interface and - // the instance's specific requirement. Here we remember a random instance so - // we can get the information regarding the generated interface. - llvm::StringMap availClasses; - for (const Availability &avail : opAvailabilities) - availClasses.try_emplace(avail.getClass(), avail); - for (const NamedAttribute &namedAttr : srcOp.getAttributes()) { - const auto *enumAttr = llvm::dyn_cast(&namedAttr.attr); - if (!enumAttr) - continue; - - for (const EnumAttrCase &enumerant : enumAttr->getAllCases()) - for (const Availability &caseAvail : - getAvailabilities(enumerant.getDef())) - availClasses.try_emplace(caseAvail.getClass(), caseAvail); - } - - // Then generate implementation for each availability class. - for (const auto &availClass : availClasses) { - StringRef availClassName = availClass.getKey(); - Availability avail = availClass.getValue(); - - // Generate the implementation method signature. - os << formatv("{0} {1}::{2}() {{\n", avail.getQueryFnRetType(), - srcOp.getCppClassName(), avail.getQueryFnName()); - - // Create the variable for the final requirement and initialize it. - os << formatv(" {0} tblgen_overall = {1};\n", avail.getQueryFnRetType(), - avail.getMergeInitializer()); - - // Update with the op's specific availability spec. - for (const Availability &avail : opAvailabilities) - if (avail.getClass() == availClassName && - (!avail.getMergeInstancePreparation().empty() || - !avail.getMergeActionCode().empty())) { - os << " {\n " - // Prepare this instance. - << avail.getMergeInstancePreparation() - << "\n " - // Merge this instance. - << std::string( - tgfmt(avail.getMergeActionCode(), - &fctx.addSubst("instance", avail.getMergeInstance()))) - << ";\n }\n"; - } - - // Update with enum attributes' specific availability spec. - for (const NamedAttribute &namedAttr : srcOp.getAttributes()) { - const auto *enumAttr = llvm::dyn_cast(&namedAttr.attr); - if (!enumAttr) - continue; - - // (enumerant, availability specification) pairs for this availability - // class. - SmallVector, 1> caseSpecs; - - // Collect all cases' availability specs. - for (const EnumAttrCase &enumerant : enumAttr->getAllCases()) - for (const Availability &caseAvail : - getAvailabilities(enumerant.getDef())) - if (availClassName == caseAvail.getClass()) - caseSpecs.push_back({enumerant, caseAvail}); - - // If this attribute kind does not have any availability spec from any of - // its cases, no more work to do. - if (caseSpecs.empty()) - continue; - - if (enumAttr->isBitEnum()) { - // For BitEnumAttr, we need to iterate over each bit to query its - // availability spec. - os << formatv(" for (unsigned i = 0; " - "i < std::numeric_limits<{0}>::digits; ++i) {{\n", - enumAttr->getUnderlyingType()); - os << formatv(" {0}::{1} tblgen_attrVal = this->{2}() & " - "static_cast<{0}::{1}>(1 << i);\n", - enumAttr->getCppNamespace(), enumAttr->getEnumClassName(), - namedAttr.name); - os << formatv( - " if (static_cast<{0}>(tblgen_attrVal) == 0) continue;\n", - enumAttr->getUnderlyingType()); - } else { - // For IntEnumAttr, we just need to query the value as a whole. - os << " {\n"; - os << formatv(" auto tblgen_attrVal = this->{0}();\n", - namedAttr.name); - } - os << formatv(" auto tblgen_instance = {0}::{1}(tblgen_attrVal);\n", - enumAttr->getCppNamespace(), avail.getQueryFnName()); - os << " if (tblgen_instance) " - // TODO` here once ODS supports - // dialect-specific contents so that we can use not implementing the - // availability interface as indication of no requirements. - << std::string(tgfmt(caseSpecs.front().second.getMergeActionCode(), - &fctx.addSubst("instance", "*tblgen_instance"))) - << ";\n"; - os << " }\n"; - } - - os << " return tblgen_overall;\n"; - os << "}\n"; - } -} - -static bool emitAvailabilityImpl(const RecordKeeper &recordKeeper, - raw_ostream &os) { - llvm::emitSourceFileHeader("SPIR-V Op Availability Implementations", os); - - auto defs = recordKeeper.getAllDerivedDefinitions("SPV_Op"); - for (const auto *def : defs) { - Operator op(def); - emitAvailabilityImpl(op, os); - } - return false; -} - -//===----------------------------------------------------------------------===// -// Op Availability Implementation Hook Registration -//===----------------------------------------------------------------------===// - -static mlir::GenRegistration - genOpAvailabilityImpl("gen-spirv-avail-impls", - "Generate SPIR-V operation utility definitions", - [](const RecordKeeper &records, raw_ostream &os) { - return emitAvailabilityImpl(records, os); - }); - //===----------------------------------------------------------------------===// // SPIR-V Capability Implication AutoGen //===----------------------------------------------------------------------===// diff --git a/mlir/utils/spirv/gen_spirv_dialect.py b/mlir/utils/spirv/gen_spirv_dialect.py --- a/mlir/utils/spirv/gen_spirv_dialect.py +++ b/mlir/utils/spirv/gen_spirv_dialect.py @@ -320,8 +320,7 @@ exts == DEFAULT_EXT): joined_spec = ',\n '.join( [e for e in [min_version, max_version, exts, caps] if e]) - avail = '{} availability = [\n {}\n ];'.format( - 'let' if for_op else 'list', joined_spec) + avail = 'let availability = [\n {}\n ];'.format(joined_spec) return '{}{}{}'.format(implies, '\n ' if implies and avail else '', avail) diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel @@ -3473,11 +3473,11 @@ "include/mlir/Dialect/SPIRV/IR/SPIRVEnums.cpp.inc", ), ( - ["-gen-spirv-enum-avail-decls"], + ["-gen-enum-avail-decls"], "include/mlir/Dialect/SPIRV/IR/SPIRVEnumAvailability.h.inc", ), ( - ["-gen-spirv-enum-avail-defs"], + ["-gen-enum-avail-defs"], "include/mlir/Dialect/SPIRV/IR/SPIRVEnumAvailability.cpp.inc", ), ( @@ -3516,10 +3516,6 @@ ["-gen-avail-interface-defs"], "include/mlir/Dialect/SPIRV/IR/SPIRVAvailability.cpp.inc", ), - ( - ["-gen-spirv-avail-impls"], - "include/mlir/Dialect/SPIRV/IR/SPIRVOpAvailabilityImpl.inc", - ), ], tblgen = ":mlir-tblgen", td_file = "include/mlir/Dialect/SPIRV/IR/SPIRVOps.td", diff --git a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel @@ -98,6 +98,22 @@ ["-gen-rewriters"], "lib/Dialect/Test/TestPatterns.inc", ), + ( + ["-gen-avail-interface-decls"], + "lib/Dialect/Test/TestOpAvailability.h.inc", + ), + ( + ["-gen-avail-interface-defs"], + "lib/Dialect/Test/TestOpAvailability.cpp.inc", + ), + ( + ["-gen-enum-avail-decls"], + "lib/Dialect/Test/TestEnumAvailability.h.inc", + ), + ( + ["-gen-enum-avail-defs"], + "lib/Dialect/Test/TestEnumAvailability.cpp.inc", + ), ], tblgen = "//mlir:mlir-tblgen", td_file = "lib/Dialect/Test/TestOps.td", @@ -200,6 +216,7 @@ "lib/Dialect/Test/TestAttributes.cpp", "lib/Dialect/Test/TestDialect.cpp", "lib/Dialect/Test/TestInterfaces.cpp", + "lib/Dialect/Test/TestOpAvailability.cpp", "lib/Dialect/Test/TestPatterns.cpp", "lib/Dialect/Test/TestTraits.cpp", "lib/Dialect/Test/TestTypes.cpp",