1 From 28a883ba4c67f58a9540fb0651c647bb02883622 Mon Sep 17 00:00:00 2001
2 From: David Neto <dneto@google.com>
3 Date: Wed, 25 Jun 2025 11:27:23 -0400
4 Subject: [PATCH] SPV_INTEL_function_variants: basic asm, dis support (#6195)
6 The challenging part is that there are instructions that
7 take zero or more Capability operands. So we have to introduce
8 SPV_TYPE_OPERAND_VARIABLE_CAPABILITY and SPV_TYPE_OPERAND_OPTIONAL_CAPABILITY.
10 Remove deprecated enums for the first and last variable or optional
12 Upstream-Status: Backport [https://github.com/KhronosGroup/SPIRV-Tools/commit/28a883ba4c67f58a9540fb0651c647bb02883622]
13 Signed-off-by: Khem Raj <raj.khem@gmail.com>
16 include/spirv-tools/libspirv.h | 48 +++++++----------
17 source/binary.cpp | 3 ++
18 source/disassemble.cpp | 1 +
19 source/operand.cpp | 7 +++
20 test/text_to_binary.extension_test.cpp | 73 ++++++++++++++++++++++++++
22 7 files changed, 107 insertions(+), 30 deletions(-)
24 diff --git a/DEPS b/DEPS
25 index e25ca513..511fd718 100644
28 @@ -14,7 +14,7 @@ vars = {
30 're2_revision': 'c84a140c93352cdabbfb547c531be34515b12228',
32 - 'spirv_headers_revision': '2a611a970fdbc41ac2e3e328802aed9985352dca',
33 + 'spirv_headers_revision': '9e3836d7d6023843a72ecd3fbf3f09b1b6747a9e',
35 'mimalloc_revision': '09a27098aa6e9286518bd9c74e6ffa7199c3f04e',
37 diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
38 index a2a032a0..2a604e94 100644
39 --- a/include/spirv-tools/libspirv.h
40 +++ b/include/spirv-tools/libspirv.h
41 @@ -189,36 +189,24 @@ typedef enum spv_operand_type_t {
42 SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26
43 SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR
45 -// NOTE: New concrete enum values should be added at the end.
47 -// The "optional" and "variable" operand types are only used internally by
48 -// the assembler and the binary parser.
49 -// There are two categories:
50 -// Optional : expands to 0 or 1 operand, like ? in regular expressions.
51 -// Variable : expands to 0, 1 or many operands or pairs of operands.
52 -// This is similar to * in regular expressions.
54 -// NOTE: These FIRST_* and LAST_* enum values are DEPRECATED.
55 -// The concept of "optional" and "variable" operand types are only intended
56 -// for use as an implementation detail of parsing SPIR-V, either in text or
57 -// binary form. Instead of using enum ranges, use characteristic function
58 -// spvOperandIsConcrete.
59 -// The use of enum value ranges in a public API makes it difficult to insert
60 -// new values into a range without also breaking binary compatibility.
62 -// Macros for defining bounds on optional and variable operand types.
63 -// Any variable operand type is also optional.
64 -// TODO(dneto): Remove SPV_OPERAND_TYPE_FIRST_* and SPV_OPERAND_TYPE_LAST_*
65 -#define FIRST_OPTIONAL(ENUM) ENUM, SPV_OPERAND_TYPE_FIRST_OPTIONAL_TYPE = ENUM
66 -#define FIRST_VARIABLE(ENUM) ENUM, SPV_OPERAND_TYPE_FIRST_VARIABLE_TYPE = ENUM
67 -#define LAST_VARIABLE(ENUM) \
68 - ENUM, SPV_OPERAND_TYPE_LAST_VARIABLE_TYPE = ENUM, \
69 - SPV_OPERAND_TYPE_LAST_OPTIONAL_TYPE = ENUM
70 + // NOTE: New concrete enum values should be added at the end.
72 + // The "optional" and "variable" operand types are only used internally by
73 + // the assembler and the binary parser.
74 + // There are two categories:
75 + // Optional : expands to 0 or 1 operand, like ? in regular expressions.
76 + // Variable : expands to 0, 1 or many operands or pairs of operands.
77 + // This is similar to * in regular expressions.
79 + // Use characteristic function spvOperandIsConcrete to classify the
80 + // operand types; when it returns false, the operand is optional or variable.
82 + // Any variable operand type is also optional.
84 // An optional operand represents zero or one logical operands.
85 // In an instruction definition, this may only appear at the end of the
87 - FIRST_OPTIONAL(SPV_OPERAND_TYPE_OPTIONAL_ID),
88 + SPV_OPERAND_TYPE_OPTIONAL_ID,
89 // An optional image operand type.
90 SPV_OPERAND_TYPE_OPTIONAL_IMAGE,
91 // An optional memory access type.
92 @@ -243,7 +231,7 @@ typedef enum spv_operand_type_t {
93 // A variable operand represents zero or more logical operands.
94 // In an instruction definition, this may only appear at the end of the
96 - FIRST_VARIABLE(SPV_OPERAND_TYPE_VARIABLE_ID),
97 + SPV_OPERAND_TYPE_VARIABLE_ID,
98 SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER,
99 // A sequence of zero or more pairs of (typed literal integer, Id).
100 // Expands to zero or more:
101 @@ -251,7 +239,7 @@ typedef enum spv_operand_type_t {
102 // where the literal number must always be an integer of some sort.
103 SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID,
104 // A sequence of zero or more pairs of (Id, Literal integer)
105 - LAST_VARIABLE(SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER),
106 + SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER,
108 // The following are concrete enum types from the DebugInfo extended
110 @@ -343,6 +331,10 @@ typedef enum spv_operand_type_t {
111 SPV_OPERAND_TYPE_TENSOR_OPERANDS,
112 SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS,
114 + // SPV_INTEL_function_variants
115 + SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY,
116 + SPV_OPERAND_TYPE_VARIABLE_CAPABILITY,
118 // This is a sentinel value, and does not represent an operand type.
119 // It should come last.
120 SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
121 diff --git a/source/binary.cpp b/source/binary.cpp
122 index 180d0a99..8e4d899f 100644
123 --- a/source/binary.cpp
124 +++ b/source/binary.cpp
125 @@ -636,6 +636,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
128 case SPV_OPERAND_TYPE_CAPABILITY:
129 + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY:
130 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
131 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
132 case SPV_OPERAND_TYPE_MEMORY_MODEL:
133 @@ -689,6 +690,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
134 parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT;
135 if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING)
136 parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING;
137 + if (type == SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY)
138 + parsed_operand.type = SPV_OPERAND_TYPE_CAPABILITY;
140 const spvtools::OperandDesc* entry = nullptr;
141 if (spvtools::LookupOperand(type, word, &entry)) {
142 diff --git a/source/disassemble.cpp b/source/disassemble.cpp
143 index 2d9bb0ff..4267333a 100644
144 --- a/source/disassemble.cpp
145 +++ b/source/disassemble.cpp
146 @@ -907,6 +907,7 @@ void InstructionDisassembler::EmitOperand(std::ostream& stream,
149 case SPV_OPERAND_TYPE_CAPABILITY:
150 + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY:
151 case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
152 case SPV_OPERAND_TYPE_EXECUTION_MODEL:
153 case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
154 diff --git a/source/operand.cpp b/source/operand.cpp
155 index c635c72d..d7fc535c 100644
156 --- a/source/operand.cpp
157 +++ b/source/operand.cpp
158 @@ -111,6 +111,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
159 case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO:
160 return "kernel profiling info";
161 case SPV_OPERAND_TYPE_CAPABILITY:
162 + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY:
164 case SPV_OPERAND_TYPE_RAY_FLAGS:
166 @@ -394,6 +395,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) {
167 case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS:
168 case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING:
169 case SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS:
170 + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY:
174 @@ -408,6 +410,7 @@ bool spvOperandIsVariable(spv_operand_type_t type) {
175 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER:
176 case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID:
177 case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER:
178 + case SPV_OPERAND_TYPE_VARIABLE_CAPABILITY:
182 @@ -439,6 +442,10 @@ bool spvExpandOperandSequenceOnce(spv_operand_type_t type,
183 pattern->push_back(SPV_OPERAND_TYPE_LITERAL_INTEGER);
184 pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID);
186 + case SPV_OPERAND_TYPE_VARIABLE_CAPABILITY:
187 + pattern->push_back(type);
188 + pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY);
193 diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp
194 index 65079d1b..39accfc1 100644
195 --- a/test/text_to_binary.extension_test.cpp
196 +++ b/test/text_to_binary.extension_test.cpp
197 @@ -1495,5 +1495,78 @@ INSTANTIATE_TEST_SUITE_P(
198 SaturatedToLargestFloat8NormalConversionEXT)})},
201 +// SPV_INTEL_function_variants
202 +// https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_function_variants.asciidoc
203 +INSTANTIATE_TEST_SUITE_P(
204 + SPV_INTEL_function_variants, ExtensionRoundTripTest,
206 + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6),
207 + ValuesIn(std::vector<AssemblyCase>{
208 + {"OpExtension \"SPV_INTEL_function_variants\"\n",
209 + MakeInstruction(spv::Op::OpExtension,
210 + MakeVector("SPV_INTEL_function_variants"))},
211 + {"OpCapability SpecConditionalINTEL\n",
213 + spv::Op::OpCapability,
214 + {(uint32_t)spv::Capability::SpecConditionalINTEL})},
215 + {"OpCapability FunctionVariantsINTEL\n",
217 + spv::Op::OpCapability,
218 + {(uint32_t)spv::Capability::FunctionVariantsINTEL})},
219 + {"OpDecorate %1 ConditionalINTEL %2\n",
220 + MakeInstruction(spv::Op::OpDecorate,
221 + {1, (uint32_t)spv::Decoration::ConditionalINTEL,
224 + {"OpConditionalExtensionINTEL %1 \"foo\"\n",
225 + MakeInstruction(spv::Op::OpConditionalExtensionINTEL, {1},
226 + MakeVector("foo"))},
228 + {"OpConditionalEntryPointINTEL %1 Kernel %2 \"foo\"\n",
229 + MakeInstruction(spv::Op::OpConditionalEntryPointINTEL,
230 + {1, (uint32_t)spv::ExecutionModel::Kernel, 2},
231 + MakeVector("foo"))},
233 + {"OpConditionalCapabilityINTEL %1 Kernel\n",
234 + MakeInstruction(spv::Op::OpConditionalCapabilityINTEL,
235 + {1, (uint32_t)spv::ExecutionModel::Kernel})},
237 + {"%2 = OpSpecConstantTargetINTEL %1 42\n",
238 + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL, {1, 2, 42})},
240 + {"%2 = OpSpecConstantTargetINTEL %1 42 99\n",
241 + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL,
244 + {"%2 = OpSpecConstantTargetINTEL %1 42 99 108\n",
245 + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL,
246 + {1, 2, 42, 99, 108})},
248 + {"%2 = OpSpecConstantArchitectureINTEL %1 42 99 108 72\n",
249 + MakeInstruction(spv::Op::OpSpecConstantArchitectureINTEL,
250 + {1, 2, 42, 99, 108, 72})},
252 + {"%2 = OpSpecConstantCapabilitiesINTEL %1\n",
253 + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL, {1, 2})},
255 + {"%2 = OpSpecConstantCapabilitiesINTEL %1 Kernel\n",
256 + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL,
257 + {1, 2, (uint32_t)spv::Capability::Kernel})},
259 + {"%2 = OpSpecConstantCapabilitiesINTEL %1 Kernel Shader\n",
260 + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL,
261 + {1, 2, (uint32_t)spv::Capability::Kernel,
262 + (uint32_t)spv::Capability::Shader})},
264 + {"%2 = OpConditionalCopyObjectINTEL %1 %3 %4\n",
265 + MakeInstruction(spv::Op::OpConditionalCopyObjectINTEL,
268 + {"%2 = OpConditionalCopyObjectINTEL %1 %3 %4 %5 %6\n",
269 + MakeInstruction(spv::Op::OpConditionalCopyObjectINTEL,
270 + {1, 2, 3, 4, 5, 6})},
275 } // namespace spvtools
276 diff --git a/utils/ggt.py b/utils/ggt.py
277 index 258c1b00..45262ba8 100755
280 @@ -242,7 +242,8 @@ class Grammar():
281 'MatrixMultiplyAccumulateOperands',
282 'RawAccessChainOperands',
288 def dump(self) -> None: