1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Assembler tests for instructions in the "Extension Instruction" section
16 // of the SPIR-V spec.
17 
18 #include <string>
19 #include <tuple>
20 #include <vector>
21 
22 #include "gmock/gmock.h"
23 #include "source/latest_version_glsl_std_450_header.h"
24 #include "source/latest_version_opencl_std_header.h"
25 #include "source/util/string_utils.h"
26 #include "test/test_fixture.h"
27 #include "test/unit_spirv.h"
28 
29 namespace spvtools {
30 namespace {
31 
32 using spvtest::Concatenate;
33 using spvtest::MakeInstruction;
34 using utils::MakeVector;
35 using spvtest::TextToBinaryTest;
36 using ::testing::Combine;
37 using ::testing::Eq;
38 using ::testing::Values;
39 using ::testing::ValuesIn;
40 
41 // Returns a generator of common Vulkan environment values to be tested.
CommonVulkanEnvs()42 std::vector<spv_target_env> CommonVulkanEnvs() {
43   return {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
44           SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,    SPV_ENV_VULKAN_1_1};
45 }
46 
TEST_F(TextToBinaryTest,InvalidExtInstImportName)47 TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
48   EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
49               Eq("Invalid extended instruction import 'Haskell.std'"));
50 }
51 
TEST_F(TextToBinaryTest,InvalidImportId)52 TEST_F(TextToBinaryTest, InvalidImportId) {
53   EXPECT_THAT(CompileFailure("%1 = OpTypeVoid\n"
54                              "%2 = OpExtInst %1 %1"),
55               Eq("Invalid extended instruction import Id 2"));
56 }
57 
TEST_F(TextToBinaryTest,InvalidImportInstruction)58 TEST_F(TextToBinaryTest, InvalidImportInstruction) {
59   const std::string input = R"(%1 = OpTypeVoid
60                                %2 = OpExtInstImport "OpenCL.std"
61                                %3 = OpExtInst %1 %2 not_in_the_opencl)";
62   EXPECT_THAT(CompileFailure(input),
63               Eq("Invalid extended instruction name 'not_in_the_opencl'."));
64 }
65 
TEST_F(TextToBinaryTest,MultiImport)66 TEST_F(TextToBinaryTest, MultiImport) {
67   const std::string input = R"(%2 = OpExtInstImport "OpenCL.std"
68                                %2 = OpExtInstImport "OpenCL.std")";
69   EXPECT_THAT(CompileFailure(input),
70               Eq("Import Id is being defined a second time"));
71 }
72 
TEST_F(TextToBinaryTest,TooManyArguments)73 TEST_F(TextToBinaryTest, TooManyArguments) {
74   const std::string input = R"(%opencl = OpExtInstImport "OpenCL.std"
75                                %2 = OpExtInst %float %opencl cos %x %oops")";
76   EXPECT_THAT(CompileFailure(input), Eq("Expected '=', found end of stream."));
77 }
78 
79 TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
80   const std::string input = R"(%1 = OpExtInstImport "OpenCL.std"
81 %2 = OpExtInstImport "GLSL.std.450"
82 %4 = OpExtInst %3 %1 native_sqrt %5
83 %7 = OpExtInst %6 %2 MatrixInverse %8
84 )";
85 
86   // Make sure it assembles correctly.
87   EXPECT_THAT(
88       CompiledInstructions(input),
89       Eq(Concatenate({
90           MakeInstruction(spv::Op::OpExtInstImport, {1},
91                           MakeVector("OpenCL.std")),
92           MakeInstruction(spv::Op::OpExtInstImport, {2},
93                           MakeVector("GLSL.std.450")),
94           MakeInstruction(
95               spv::Op::OpExtInst,
96               {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
97           MakeInstruction(spv::Op::OpExtInst,
98                           {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
99       })));
100 
101   // Make sure it disassembles correctly.
102   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
103 }
104 
105 // A test case for assembling into words in an instruction.
106 struct AssemblyCase {
107   std::string input;
108   std::vector<uint32_t> expected;
109 };
110 
111 using ExtensionAssemblyTest = spvtest::TextToBinaryTestBase<
112     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
113 
114 TEST_P(ExtensionAssemblyTest, Samples) {
115   const spv_target_env& env = std::get<0>(GetParam());
116   const AssemblyCase& ac = std::get<1>(GetParam());
117 
118   // Check that it assembles correctly.
119   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
120 }
121 
122 using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
123     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
124 
125 TEST_P(ExtensionRoundTripTest, Samples) {
126   const spv_target_env& env = std::get<0>(GetParam());
127   const AssemblyCase& ac = std::get<1>(GetParam());
128 
129   // Check that it assembles correctly.
130   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
131 
132   // Check round trip through the disassembler.
133   EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
134                                           SPV_BINARY_TO_TEXT_OPTION_NONE, env),
135               Eq(ac.input))
136       << "target env: " << spvTargetEnvDescription(env) << "\n";
137 }
138 
139 // SPV_KHR_shader_ballot
140 
141 INSTANTIATE_TEST_SUITE_P(
142     SPV_KHR_shader_ballot, ExtensionRoundTripTest,
143     // We'll get coverage over operand tables by trying the universal
144     // environments, and at least one specific environment.
145     Combine(
146         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
147                SPV_ENV_VULKAN_1_0),
148         ValuesIn(std::vector<AssemblyCase>{
149             {"OpCapability SubgroupBallotKHR\n",
150              MakeInstruction(spv::Op::OpCapability,
151                              {uint32_t(spv::Capability::SubgroupBallotKHR)})},
152             {"%2 = OpSubgroupBallotKHR %1 %3\n",
153              MakeInstruction(spv::Op::OpSubgroupBallotKHR, {1, 2, 3})},
154             {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
155              MakeInstruction(spv::Op::OpSubgroupFirstInvocationKHR, {1, 2, 3})},
156             {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
157              MakeInstruction(spv::Op::OpDecorate,
158                              {1, uint32_t(spv::Decoration::BuiltIn),
159                               uint32_t(spv::BuiltIn::SubgroupEqMaskKHR)})},
160             {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
161              MakeInstruction(spv::Op::OpDecorate,
162                              {1, uint32_t(spv::Decoration::BuiltIn),
163                               uint32_t(spv::BuiltIn::SubgroupGeMaskKHR)})},
164             {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
165              MakeInstruction(spv::Op::OpDecorate,
166                              {1, uint32_t(spv::Decoration::BuiltIn),
167                               uint32_t(spv::BuiltIn::SubgroupGtMaskKHR)})},
168             {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
169              MakeInstruction(spv::Op::OpDecorate,
170                              {1, uint32_t(spv::Decoration::BuiltIn),
171                               uint32_t(spv::BuiltIn::SubgroupLeMaskKHR)})},
172             {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
173              MakeInstruction(spv::Op::OpDecorate,
174                              {1, uint32_t(spv::Decoration::BuiltIn),
175                               uint32_t(spv::BuiltIn::SubgroupLtMaskKHR)})},
176         })));
177 
178 INSTANTIATE_TEST_SUITE_P(
179     SPV_KHR_shader_ballot_vulkan_1_1, ExtensionRoundTripTest,
180     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
181     // builtin enums.
182     Combine(
183         Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
184         ValuesIn(std::vector<AssemblyCase>{
185             {"OpCapability SubgroupBallotKHR\n",
186              MakeInstruction(spv::Op::OpCapability,
187                              {(uint32_t)spv::Capability::SubgroupBallotKHR})},
188             {"%2 = OpSubgroupBallotKHR %1 %3\n",
189              MakeInstruction(spv::Op::OpSubgroupBallotKHR, {1, 2, 3})},
190             {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
191              MakeInstruction(spv::Op::OpSubgroupFirstInvocationKHR, {1, 2, 3})},
192             {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
193              MakeInstruction(spv::Op::OpDecorate,
194                              {1, uint32_t(spv::Decoration::BuiltIn),
195                               uint32_t(spv::BuiltIn::SubgroupEqMask)})},
196             {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
197              MakeInstruction(spv::Op::OpDecorate,
198                              {1, uint32_t(spv::Decoration::BuiltIn),
199                               uint32_t(spv::BuiltIn::SubgroupGeMask)})},
200             {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
201              MakeInstruction(spv::Op::OpDecorate,
202                              {1, uint32_t(spv::Decoration::BuiltIn),
203                               uint32_t(spv::BuiltIn::SubgroupGtMask)})},
204             {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
205              MakeInstruction(spv::Op::OpDecorate,
206                              {1, uint32_t(spv::Decoration::BuiltIn),
207                               uint32_t(spv::BuiltIn::SubgroupLeMask)})},
208             {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
209              MakeInstruction(spv::Op::OpDecorate,
210                              {1, uint32_t(spv::Decoration::BuiltIn),
211                               uint32_t(spv::BuiltIn::SubgroupLtMask)})},
212         })));
213 
214 // The old builtin names (with KHR suffix) still work in the assembler, and
215 // map to the enums without the KHR.
216 INSTANTIATE_TEST_SUITE_P(
217     SPV_KHR_shader_ballot_vulkan_1_1_alias_check, ExtensionAssemblyTest,
218     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
219     // builtin enums.
220     Combine(Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
221             ValuesIn(std::vector<AssemblyCase>{
222                 {"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
223                  MakeInstruction(spv::Op::OpDecorate,
224                                  {1, (uint32_t)spv::Decoration::BuiltIn,
225                                   (uint32_t)spv::BuiltIn::SubgroupEqMask})},
226                 {"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
227                  MakeInstruction(spv::Op::OpDecorate,
228                                  {1, (uint32_t)spv::Decoration::BuiltIn,
229                                   (uint32_t)spv::BuiltIn::SubgroupGeMask})},
230                 {"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
231                  MakeInstruction(spv::Op::OpDecorate,
232                                  {1, (uint32_t)spv::Decoration::BuiltIn,
233                                   (uint32_t)spv::BuiltIn::SubgroupGtMask})},
234                 {"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
235                  MakeInstruction(spv::Op::OpDecorate,
236                                  {1, (uint32_t)spv::Decoration::BuiltIn,
237                                   (uint32_t)spv::BuiltIn::SubgroupLeMask})},
238                 {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
239                  MakeInstruction(spv::Op::OpDecorate,
240                                  {1, (uint32_t)spv::Decoration::BuiltIn,
241                                   (uint32_t)spv::BuiltIn::SubgroupLtMask})},
242             })));
243 
244 // SPV_KHR_shader_draw_parameters
245 
246 INSTANTIATE_TEST_SUITE_P(
247     SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest,
248     // We'll get coverage over operand tables by trying the universal
249     // environments, and at least one specific environment.
250     Combine(ValuesIn(CommonVulkanEnvs()),
251             ValuesIn(std::vector<AssemblyCase>{
252                 {"OpCapability DrawParameters\n",
253                  MakeInstruction(spv::Op::OpCapability,
254                                  {(uint32_t)spv::Capability::DrawParameters})},
255                 {"OpDecorate %1 BuiltIn BaseVertex\n",
256                  MakeInstruction(spv::Op::OpDecorate,
257                                  {1, (uint32_t)spv::Decoration::BuiltIn,
258                                   (uint32_t)spv::BuiltIn::BaseVertex})},
259                 {"OpDecorate %1 BuiltIn BaseInstance\n",
260                  MakeInstruction(spv::Op::OpDecorate,
261                                  {1, (uint32_t)spv::Decoration::BuiltIn,
262                                   (uint32_t)spv::BuiltIn::BaseInstance})},
263                 {"OpDecorate %1 BuiltIn DrawIndex\n",
264                  MakeInstruction(spv::Op::OpDecorate,
265                                  {1, (uint32_t)spv::Decoration::BuiltIn,
266                                   (uint32_t)spv::BuiltIn::DrawIndex})},
267             })));
268 
269 // SPV_KHR_subgroup_vote
270 
271 INSTANTIATE_TEST_SUITE_P(
272     SPV_KHR_subgroup_vote, ExtensionRoundTripTest,
273     // We'll get coverage over operand tables by trying the universal
274     // environments, and at least one specific environment.
275     Combine(ValuesIn(CommonVulkanEnvs()),
276             ValuesIn(std::vector<AssemblyCase>{
277                 {"OpCapability SubgroupVoteKHR\n",
278                  MakeInstruction(spv::Op::OpCapability,
279                                  {(uint32_t)spv::Capability::SubgroupVoteKHR})},
280                 {"%2 = OpSubgroupAnyKHR %1 %3\n",
281                  MakeInstruction(spv::Op::OpSubgroupAnyKHR, {1, 2, 3})},
282                 {"%2 = OpSubgroupAllKHR %1 %3\n",
283                  MakeInstruction(spv::Op::OpSubgroupAllKHR, {1, 2, 3})},
284                 {"%2 = OpSubgroupAllEqualKHR %1 %3\n",
285                  MakeInstruction(spv::Op::OpSubgroupAllEqualKHR, {1, 2, 3})},
286             })));
287 
288 // SPV_KHR_16bit_storage
289 
290 INSTANTIATE_TEST_SUITE_P(
291     SPV_KHR_16bit_storage, ExtensionRoundTripTest,
292     // We'll get coverage over operand tables by trying the universal
293     // environments, and at least one specific environment.
294     Combine(
295         ValuesIn(CommonVulkanEnvs()),
296         ValuesIn(std::vector<AssemblyCase>{
297             {"OpCapability StorageBuffer16BitAccess\n",
298              MakeInstruction(
299                  spv::Op::OpCapability,
300                  {(uint32_t)spv::Capability::StorageUniformBufferBlock16})},
301             {"OpCapability StorageBuffer16BitAccess\n",
302              MakeInstruction(
303                  spv::Op::OpCapability,
304                  {(uint32_t)spv::Capability::StorageBuffer16BitAccess})},
305             {"OpCapability UniformAndStorageBuffer16BitAccess\n",
306              MakeInstruction(
307                  spv::Op::OpCapability,
308                  {(uint32_t)
309                       spv::Capability::UniformAndStorageBuffer16BitAccess})},
310             {"OpCapability UniformAndStorageBuffer16BitAccess\n",
311              MakeInstruction(spv::Op::OpCapability,
312                              {(uint32_t)spv::Capability::StorageUniform16})},
313             {"OpCapability StoragePushConstant16\n",
314              MakeInstruction(
315                  spv::Op::OpCapability,
316                  {(uint32_t)spv::Capability::StoragePushConstant16})},
317             {"OpCapability StorageInputOutput16\n",
318              MakeInstruction(
319                  spv::Op::OpCapability,
320                  {(uint32_t)spv::Capability::StorageInputOutput16})},
321         })));
322 
323 INSTANTIATE_TEST_SUITE_P(
324     SPV_KHR_16bit_storage_alias_check, ExtensionAssemblyTest,
325     Combine(
326         ValuesIn(CommonVulkanEnvs()),
327         ValuesIn(std::vector<AssemblyCase>{
328             // The old name maps to the new enum.
329             {"OpCapability StorageUniformBufferBlock16\n",
330              MakeInstruction(
331                  spv::Op::OpCapability,
332                  {(uint32_t)spv::Capability::StorageBuffer16BitAccess})},
333             // The new name maps to the old enum.
334             {"OpCapability UniformAndStorageBuffer16BitAccess\n",
335              MakeInstruction(spv::Op::OpCapability,
336                              {(uint32_t)spv::Capability::StorageUniform16})},
337         })));
338 
339 // SPV_KHR_device_group
340 
341 INSTANTIATE_TEST_SUITE_P(
342     SPV_KHR_device_group, ExtensionRoundTripTest,
343     // We'll get coverage over operand tables by trying the universal
344     // environments, and at least one specific environment.
345     Combine(ValuesIn(CommonVulkanEnvs()),
346             ValuesIn(std::vector<AssemblyCase>{
347                 {"OpCapability DeviceGroup\n",
348                  MakeInstruction(spv::Op::OpCapability,
349                                  {(uint32_t)spv::Capability::DeviceGroup})},
350                 {"OpDecorate %1 BuiltIn DeviceIndex\n",
351                  MakeInstruction(spv::Op::OpDecorate,
352                                  {1, (uint32_t)spv::Decoration::BuiltIn,
353                                   (uint32_t)spv::BuiltIn::DeviceIndex})},
354             })));
355 
356 // SPV_KHR_8bit_storage
357 
358 INSTANTIATE_TEST_SUITE_P(
359     SPV_KHR_8bit_storage, ExtensionRoundTripTest,
360     // We'll get coverage over operand tables by trying the universal
361     // environments, and at least one specific environment.
362     Combine(ValuesIn(CommonVulkanEnvs()),
363             ValuesIn(std::vector<AssemblyCase>{
364                 {"OpCapability StorageBuffer8BitAccess\n",
365                  MakeInstruction(
366                      spv::Op::OpCapability,
367                      {(uint32_t)spv::Capability::StorageBuffer8BitAccess})},
368                 {"OpCapability UniformAndStorageBuffer8BitAccess\n",
369                  MakeInstruction(
370                      spv::Op::OpCapability,
371                      {(uint32_t)
372                           spv::Capability::UniformAndStorageBuffer8BitAccess})},
373                 {"OpCapability StoragePushConstant8\n",
374                  MakeInstruction(
375                      spv::Op::OpCapability,
376                      {(uint32_t)spv::Capability::StoragePushConstant8})},
377             })));
378 
379 // SPV_KHR_multiview
380 
381 INSTANTIATE_TEST_SUITE_P(
382     SPV_KHR_multiview, ExtensionRoundTripTest,
383     // We'll get coverage over operand tables by trying the universal
384     // environments, and at least one specific environment.
385     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
386                    SPV_ENV_VULKAN_1_0),
387             ValuesIn(std::vector<AssemblyCase>{
388                 {"OpCapability MultiView\n",
389                  MakeInstruction(spv::Op::OpCapability,
390                                  {(uint32_t)spv::Capability::MultiView})},
391                 {"OpDecorate %1 BuiltIn ViewIndex\n",
392                  MakeInstruction(spv::Op::OpDecorate,
393                                  {1, (uint32_t)spv::Decoration::BuiltIn,
394                                   (uint32_t)spv::BuiltIn::ViewIndex})},
395             })));
396 
397 // SPV_AMD_shader_explicit_vertex_parameter
398 
399 #define PREAMBLE \
400   "%1 = OpExtInstImport \"SPV_AMD_shader_explicit_vertex_parameter\"\n"
401 INSTANTIATE_TEST_SUITE_P(
402     SPV_AMD_shader_explicit_vertex_parameter, ExtensionRoundTripTest,
403     // We'll get coverage over operand tables by trying the universal
404     // environments, and at least one specific environment.
405     Combine(
406         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
407                SPV_ENV_VULKAN_1_0),
408         ValuesIn(std::vector<AssemblyCase>{
409             {PREAMBLE "%3 = OpExtInst %2 %1 InterpolateAtVertexAMD %4 %5\n",
410              Concatenate(
411                  {MakeInstruction(
412                       spv::Op::OpExtInstImport, {1},
413                       MakeVector("SPV_AMD_shader_explicit_vertex_parameter")),
414                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 1, 4, 5})})},
415         })));
416 #undef PREAMBLE
417 
418 // SPV_AMD_shader_trinary_minmax
419 
420 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_trinary_minmax\"\n"
421 INSTANTIATE_TEST_SUITE_P(
422     SPV_AMD_shader_trinary_minmax, ExtensionRoundTripTest,
423     // We'll get coverage over operand tables by trying the universal
424     // environments, and at least one specific environment.
425     Combine(
426         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
427                SPV_ENV_VULKAN_1_0),
428         ValuesIn(std::vector<AssemblyCase>{
429             {PREAMBLE "%3 = OpExtInst %2 %1 FMin3AMD %4 %5 %6\n",
430              Concatenate(
431                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
432                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
433                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 1, 4, 5, 6})})},
434             {PREAMBLE "%3 = OpExtInst %2 %1 UMin3AMD %4 %5 %6\n",
435              Concatenate(
436                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
437                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
438                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 2, 4, 5, 6})})},
439             {PREAMBLE "%3 = OpExtInst %2 %1 SMin3AMD %4 %5 %6\n",
440              Concatenate(
441                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
442                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
443                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 3, 4, 5, 6})})},
444             {PREAMBLE "%3 = OpExtInst %2 %1 FMax3AMD %4 %5 %6\n",
445              Concatenate(
446                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
447                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
448                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 4, 4, 5, 6})})},
449             {PREAMBLE "%3 = OpExtInst %2 %1 UMax3AMD %4 %5 %6\n",
450              Concatenate(
451                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
452                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
453                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 5, 4, 5, 6})})},
454             {PREAMBLE "%3 = OpExtInst %2 %1 SMax3AMD %4 %5 %6\n",
455              Concatenate(
456                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
457                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
458                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 6, 4, 5, 6})})},
459             {PREAMBLE "%3 = OpExtInst %2 %1 FMid3AMD %4 %5 %6\n",
460              Concatenate(
461                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
462                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
463                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 7, 4, 5, 6})})},
464             {PREAMBLE "%3 = OpExtInst %2 %1 UMid3AMD %4 %5 %6\n",
465              Concatenate(
466                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
467                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
468                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 8, 4, 5, 6})})},
469             {PREAMBLE "%3 = OpExtInst %2 %1 SMid3AMD %4 %5 %6\n",
470              Concatenate(
471                  {MakeInstruction(spv::Op::OpExtInstImport, {1},
472                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
473                   MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 9, 4, 5, 6})})},
474         })));
475 #undef PREAMBLE
476 
477 // SPV_AMD_gcn_shader
478 
479 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
480 INSTANTIATE_TEST_SUITE_P(
481     SPV_AMD_gcn_shader, ExtensionRoundTripTest,
482     // We'll get coverage over operand tables by trying the universal
483     // environments, and at least one specific environment.
484     Combine(
485         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
486                SPV_ENV_VULKAN_1_0),
487         ValuesIn(std::vector<AssemblyCase>{
488             {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
489              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
490                                           MakeVector("SPV_AMD_gcn_shader")),
491                           MakeInstruction(spv::Op::OpExtInst,
492                                           {2, 3, 1, 1, 4})})},
493             {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
494              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
495                                           MakeVector("SPV_AMD_gcn_shader")),
496                           MakeInstruction(spv::Op::OpExtInst,
497                                           {2, 3, 1, 2, 4})})},
498             {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
499              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
500                                           MakeVector("SPV_AMD_gcn_shader")),
501                           MakeInstruction(spv::Op::OpExtInst, {2, 3, 1, 3})})},
502         })));
503 #undef PREAMBLE
504 
505 // SPV_AMD_shader_ballot
506 
507 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_ballot\"\n"
508 INSTANTIATE_TEST_SUITE_P(
509     SPV_AMD_shader_ballot, ExtensionRoundTripTest,
510     // We'll get coverage over operand tables by trying the universal
511     // environments, and at least one specific environment.
512     Combine(
513         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
514                SPV_ENV_VULKAN_1_0),
515         ValuesIn(std::vector<AssemblyCase>{
516             {PREAMBLE "%3 = OpExtInst %2 %1 SwizzleInvocationsAMD %4 %5\n",
517              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
518                                           MakeVector("SPV_AMD_shader_ballot")),
519                           MakeInstruction(spv::Op::OpExtInst,
520                                           {2, 3, 1, 1, 4, 5})})},
521             {PREAMBLE
522              "%3 = OpExtInst %2 %1 SwizzleInvocationsMaskedAMD %4 %5\n",
523              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
524                                           MakeVector("SPV_AMD_shader_ballot")),
525                           MakeInstruction(spv::Op::OpExtInst,
526                                           {2, 3, 1, 2, 4, 5})})},
527             {PREAMBLE "%3 = OpExtInst %2 %1 WriteInvocationAMD %4 %5 %6\n",
528              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
529                                           MakeVector("SPV_AMD_shader_ballot")),
530                           MakeInstruction(spv::Op::OpExtInst,
531                                           {2, 3, 1, 3, 4, 5, 6})})},
532             {PREAMBLE "%3 = OpExtInst %2 %1 MbcntAMD %4\n",
533              Concatenate({MakeInstruction(spv::Op::OpExtInstImport, {1},
534                                           MakeVector("SPV_AMD_shader_ballot")),
535                           MakeInstruction(spv::Op::OpExtInst,
536                                           {2, 3, 1, 4, 4})})},
537         })));
538 #undef PREAMBLE
539 
540 // SPV_KHR_variable_pointers
541 
542 INSTANTIATE_TEST_SUITE_P(
543     SPV_KHR_variable_pointers, ExtensionRoundTripTest,
544     // We'll get coverage over operand tables by trying the universal
545     // environments, and at least one specific environment.
546     Combine(
547         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
548                SPV_ENV_VULKAN_1_0),
549         ValuesIn(std::vector<AssemblyCase>{
550             {"OpCapability VariablePointers\n",
551              MakeInstruction(spv::Op::OpCapability,
552                              {(uint32_t)spv::Capability::VariablePointers})},
553             {"OpCapability VariablePointersStorageBuffer\n",
554              MakeInstruction(
555                  spv::Op::OpCapability,
556                  {(uint32_t)spv::Capability::VariablePointersStorageBuffer})},
557         })));
558 
559 // SPV_KHR_vulkan_memory_model
560 
561 INSTANTIATE_TEST_SUITE_P(
562     SPV_KHR_vulkan_memory_model, ExtensionRoundTripTest,
563     // We'll get coverage over operand tables by trying the universal
564     // environments, and at least one specific environment.
565     //
566     // Note: SPV_KHR_vulkan_memory_model adds scope enum value QueueFamilyKHR.
567     // Scope enums are used in ID definitions elsewhere, that don't know they
568     // are using particular enums.  So the assembler doesn't support assembling
569     // those enums names into the corresponding values.  So there is no asm/dis
570     // tests for those enums.
571     Combine(
572         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
573                SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
574         ValuesIn(std::vector<AssemblyCase>{
575             {"OpCapability VulkanMemoryModel\n",
576              MakeInstruction(
577                  spv::Op::OpCapability,
578                  {(uint32_t)spv::Capability::VulkanMemoryModelKHR})},
579             {"OpCapability VulkanMemoryModelDeviceScope\n",
580              MakeInstruction(
581                  spv::Op::OpCapability,
582                  {(uint32_t)spv::Capability::VulkanMemoryModelDeviceScopeKHR})},
583             {"OpMemoryModel Logical Vulkan\n",
584              MakeInstruction(spv::Op::OpMemoryModel,
585                              {(uint32_t)spv::AddressingModel::Logical,
586                               (uint32_t)spv::MemoryModel::VulkanKHR})},
587             {"OpStore %1 %2 MakePointerAvailable %3\n",
588              MakeInstruction(
589                  spv::Op::OpStore,
590                  {1, 2,
591                   (uint32_t)spv::MemoryAccessMask::MakePointerAvailableKHR,
592                   3})},
593             {"OpStore %1 %2 Volatile|MakePointerAvailable %3\n",
594              MakeInstruction(
595                  spv::Op::OpStore,
596                  {1, 2,
597                   int(spv::MemoryAccessMask::MakePointerAvailableKHR) |
598                       int(spv::MemoryAccessMask::Volatile),
599                   3})},
600             {"OpStore %1 %2 Aligned|MakePointerAvailable 4 %3\n",
601              MakeInstruction(
602                  spv::Op::OpStore,
603                  {1, 2,
604                   int(spv::MemoryAccessMask::MakePointerAvailableKHR) |
605                       int(spv::MemoryAccessMask::Aligned),
606                   4, 3})},
607             {"OpStore %1 %2 MakePointerAvailable|NonPrivatePointer %3\n",
608              MakeInstruction(
609                  spv::Op::OpStore,
610                  {1, 2,
611                   int(spv::MemoryAccessMask::MakePointerAvailableKHR) |
612                       int(spv::MemoryAccessMask::NonPrivatePointerKHR),
613                   3})},
614             {"%2 = OpLoad %1 %3 MakePointerVisible %4\n",
615              MakeInstruction(
616                  spv::Op::OpLoad,
617                  {1, 2, 3,
618                   (uint32_t)spv::MemoryAccessMask::MakePointerVisibleKHR, 4})},
619             {"%2 = OpLoad %1 %3 Volatile|MakePointerVisible %4\n",
620              MakeInstruction(
621                  spv::Op::OpLoad,
622                  {1, 2, 3,
623                   int(spv::MemoryAccessMask::MakePointerVisibleKHR) |
624                       int(spv::MemoryAccessMask::Volatile),
625                   4})},
626             {"%2 = OpLoad %1 %3 Aligned|MakePointerVisible 8 %4\n",
627              MakeInstruction(
628                  spv::Op::OpLoad,
629                  {1, 2, 3,
630                   int(spv::MemoryAccessMask::MakePointerVisibleKHR) |
631                       int(spv::MemoryAccessMask::Aligned),
632                   8, 4})},
633             {"%2 = OpLoad %1 %3 MakePointerVisible|NonPrivatePointer "
634              "%4\n",
635              MakeInstruction(
636                  spv::Op::OpLoad,
637                  {1, 2, 3,
638                   int(spv::MemoryAccessMask::MakePointerVisibleKHR) |
639                       int(spv::MemoryAccessMask::NonPrivatePointerKHR),
640                   4})},
641             {"OpCopyMemory %1 %2 "
642              "MakePointerAvailable|"
643              "MakePointerVisible|"
644              "NonPrivatePointer "
645              "%3 %4\n",
646              MakeInstruction(
647                  spv::Op::OpCopyMemory,
648                  {1, 2,
649                   (int(spv::MemoryAccessMask::MakePointerVisibleKHR) |
650                    int(spv::MemoryAccessMask::MakePointerAvailableKHR) |
651                    int(spv::MemoryAccessMask::NonPrivatePointerKHR)),
652                   3, 4})},
653             {"OpCopyMemorySized %1 %2 %3 "
654              "MakePointerAvailable|"
655              "MakePointerVisible|"
656              "NonPrivatePointer "
657              "%4 %5\n",
658              MakeInstruction(
659                  spv::Op::OpCopyMemorySized,
660                  {1, 2, 3,
661                   (int(spv::MemoryAccessMask::MakePointerVisibleKHR) |
662                    int(spv::MemoryAccessMask::MakePointerAvailableKHR) |
663                    int(spv::MemoryAccessMask::NonPrivatePointerKHR)),
664                   4, 5})},
665             // Image operands
666             {"OpImageWrite %1 %2 %3 MakeTexelAvailable "
667              "%4\n",
668              MakeInstruction(
669                  spv::Op::OpImageWrite,
670                  {1, 2, 3, int(spv::ImageOperandsMask::MakeTexelAvailableKHR),
671                   4})},
672             {"OpImageWrite %1 %2 %3 MakeTexelAvailable|NonPrivateTexel "
673              "%4\n",
674              MakeInstruction(
675                  spv::Op::OpImageWrite,
676                  {1, 2, 3,
677                   int(spv::ImageOperandsMask::MakeTexelAvailableKHR) |
678                       int(spv::ImageOperandsMask::NonPrivateTexelKHR),
679                   4})},
680             {"OpImageWrite %1 %2 %3 "
681              "MakeTexelAvailable|NonPrivateTexel|VolatileTexel "
682              "%4\n",
683              MakeInstruction(
684                  spv::Op::OpImageWrite,
685                  {1, 2, 3,
686                   int(spv::ImageOperandsMask::MakeTexelAvailableKHR) |
687                       int(spv::ImageOperandsMask::NonPrivateTexelKHR) |
688                       int(spv::ImageOperandsMask::VolatileTexelKHR),
689                   4})},
690             {"%2 = OpImageRead %1 %3 %4 MakeTexelVisible "
691              "%5\n",
692              MakeInstruction(spv::Op::OpImageRead,
693                              {1, 2, 3, 4,
694                               int(spv::ImageOperandsMask::MakeTexelVisibleKHR),
695                               5})},
696             {"%2 = OpImageRead %1 %3 %4 "
697              "MakeTexelVisible|NonPrivateTexel "
698              "%5\n",
699              MakeInstruction(
700                  spv::Op::OpImageRead,
701                  {1, 2, 3, 4,
702                   int(spv::ImageOperandsMask::MakeTexelVisibleKHR) |
703                       int(spv::ImageOperandsMask::NonPrivateTexelKHR),
704                   5})},
705             {"%2 = OpImageRead %1 %3 %4 "
706              "MakeTexelVisible|NonPrivateTexel|VolatileTexel "
707              "%5\n",
708              MakeInstruction(
709                  spv::Op::OpImageRead,
710                  {1, 2, 3, 4,
711                   int(spv::ImageOperandsMask::MakeTexelVisibleKHR) |
712                       int(spv::ImageOperandsMask::NonPrivateTexelKHR) |
713                       int(spv::ImageOperandsMask::VolatileTexelKHR),
714                   5})},
715 
716             // Memory semantics ID values are numbers put into a SPIR-V
717             // constant integer referenced by Id. There is no token for
718             // them, and so no assembler or disassembler support required.
719             // Similar for Scope ID.
720         })));
721 
722 // SPV_GOOGLE_decorate_string
723 
724 // Now that OpDecorateString is the preferred spelling for
725 // OpDecorateStringGOOGLE use that name in round trip tests, and the GOOGLE
726 // name in an assembly-only test.
727 
728 INSTANTIATE_TEST_SUITE_P(
729     SPV_GOOGLE_decorate_string, ExtensionRoundTripTest,
730     Combine(
731         // We'll get coverage over operand tables by trying the universal
732         // environments, and at least one specific environment.
733         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
734                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
735         ValuesIn(std::vector<AssemblyCase>{
736             {"OpDecorateString %1 UserSemantic \"ABC\"\n",
737              MakeInstruction(spv::Op::OpDecorateStringGOOGLE,
738                              {1, (uint32_t)spv::Decoration::HlslSemanticGOOGLE},
739                              MakeVector("ABC"))},
740             {"OpDecorateString %1 UserSemantic \"ABC\"\n",
741              MakeInstruction(spv::Op::OpDecorateString,
742                              {1, (uint32_t)spv::Decoration::UserSemantic},
743                              MakeVector("ABC"))},
744             {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n",
745              MakeInstruction(spv::Op::OpMemberDecorateStringGOOGLE,
746                              {1, 3, (uint32_t)spv::Decoration::UserSemantic},
747                              MakeVector("DEF"))},
748             {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n",
749              MakeInstruction(spv::Op::OpMemberDecorateString,
750                              {1, 3, (uint32_t)spv::Decoration::UserSemantic},
751                              MakeVector("DEF"))},
752         })));
753 
754 INSTANTIATE_TEST_SUITE_P(
755     SPV_GOOGLE_decorate_string, ExtensionAssemblyTest,
756     Combine(
757         // We'll get coverage over operand tables by trying the universal
758         // environments, and at least one specific environment.
759         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
760                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
761         ValuesIn(std::vector<AssemblyCase>{
762             {"OpDecorateStringGOOGLE %1 HlslSemanticGOOGLE \"ABC\"\n",
763              MakeInstruction(spv::Op::OpDecorateStringGOOGLE,
764                              {1, (uint32_t)spv::Decoration::HlslSemanticGOOGLE},
765                              MakeVector("ABC"))},
766             {"OpMemberDecorateStringGOOGLE %1 3 HlslSemanticGOOGLE \"DEF\"\n",
767              MakeInstruction(spv::Op::OpMemberDecorateStringGOOGLE,
768                              {1, 3,
769                               (uint32_t)spv::Decoration::HlslSemanticGOOGLE},
770                              MakeVector("DEF"))},
771         })));
772 
773 // SPV_GOOGLE_hlsl_functionality1
774 
775 // Now that CounterBuffer is the preferred spelling for HlslCounterBufferGOOGLE,
776 // use that name in round trip tests, and the GOOGLE name in an assembly-only
777 // test.
778 INSTANTIATE_TEST_SUITE_P(
779     SPV_GOOGLE_hlsl_functionality1, ExtensionRoundTripTest,
780     Combine(
781         // We'll get coverage over operand tables by trying the universal
782         // environments, and at least one specific environment.
783         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
784                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
785         // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since
786         // they are coupled together.
787         ValuesIn(std::vector<AssemblyCase>{
788             {"OpDecorateId %1 CounterBuffer %2\n",
789              MakeInstruction(
790                  spv::Op::OpDecorateId,
791                  {1, (uint32_t)spv::Decoration::HlslCounterBufferGOOGLE, 2})},
792             {"OpDecorateId %1 CounterBuffer %2\n",
793              MakeInstruction(spv::Op::OpDecorateId,
794                              {1, (uint32_t)spv::Decoration::CounterBuffer, 2})},
795         })));
796 
797 INSTANTIATE_TEST_SUITE_P(
798     SPV_GOOGLE_hlsl_functionality1, ExtensionAssemblyTest,
799     Combine(
800         // We'll get coverage over operand tables by trying the universal
801         // environments, and at least one specific environment.
802         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
803                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
804         // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since
805         // they are coupled together.
806         ValuesIn(std::vector<AssemblyCase>{
807             {"OpDecorateId %1 HlslCounterBufferGOOGLE %2\n",
808              MakeInstruction(
809                  spv::Op::OpDecorateId,
810                  {1, (uint32_t)spv::Decoration::HlslCounterBufferGOOGLE, 2})},
811         })));
812 
813 // SPV_NV_viewport_array2
814 
815 INSTANTIATE_TEST_SUITE_P(
816     SPV_NV_viewport_array2, ExtensionRoundTripTest,
817     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
818                    SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3,
819                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
820             ValuesIn(std::vector<AssemblyCase>{
821                 {"OpExtension \"SPV_NV_viewport_array2\"\n",
822                  MakeInstruction(spv::Op::OpExtension,
823                                  MakeVector("SPV_NV_viewport_array2"))},
824                 // The EXT and NV extensions have the same token number for this
825                 // capability.
826                 {"OpCapability ShaderViewportIndexLayerEXT\n",
827                  MakeInstruction(
828                      spv::Op::OpCapability,
829                      {(uint32_t)spv::Capability::ShaderViewportIndexLayerNV})},
830                 // Check the new capability's token number
831                 {"OpCapability ShaderViewportIndexLayerEXT\n",
832                  MakeInstruction(spv::Op::OpCapability, {5254})},
833                 // Decorations
834                 {"OpDecorate %1 ViewportRelativeNV\n",
835                  MakeInstruction(
836                      spv::Op::OpDecorate,
837                      {1, (uint32_t)spv::Decoration::ViewportRelativeNV})},
838                 {"OpDecorate %1 BuiltIn ViewportMaskNV\n",
839                  MakeInstruction(spv::Op::OpDecorate,
840                                  {1, (uint32_t)spv::Decoration::BuiltIn,
841                                   (uint32_t)spv::BuiltIn::ViewportMaskNV})},
842             })));
843 
844 // SPV_NV_shader_subgroup_partitioned
845 
846 INSTANTIATE_TEST_SUITE_P(
847     SPV_NV_shader_subgroup_partitioned, ExtensionRoundTripTest,
848     Combine(
849         Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
850         ValuesIn(std::vector<AssemblyCase>{
851             {"OpExtension \"SPV_NV_shader_subgroup_partitioned\"\n",
852              MakeInstruction(spv::Op::OpExtension,
853                              MakeVector("SPV_NV_shader_subgroup_partitioned"))},
854             {"OpCapability GroupNonUniformPartitionedNV\n",
855              MakeInstruction(
856                  spv::Op::OpCapability,
857                  {(uint32_t)spv::Capability::GroupNonUniformPartitionedNV})},
858             // Check the new capability's token number
859             {"OpCapability GroupNonUniformPartitionedNV\n",
860              MakeInstruction(spv::Op::OpCapability, {5297})},
861             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
862              MakeInstruction(spv::Op::OpGroupNonUniformPartitionNV, {1, 2, 3})},
863             // Check the new instruction's token number
864             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
865              MakeInstruction(static_cast<spv::Op>(5296), {1, 2, 3})},
866             // Check the new group operations
867             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
868              MakeInstruction(
869                  spv::Op::OpGroupIAdd,
870                  {1, 2, 3, (uint32_t)spv::GroupOperation::PartitionedReduceNV,
871                   4})},
872             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
873              MakeInstruction(spv::Op::OpGroupIAdd, {1, 2, 3, 6, 4})},
874             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
875              MakeInstruction(
876                  spv::Op::OpGroupIAdd,
877                  {1, 2, 3,
878                   (uint32_t)spv::GroupOperation::PartitionedInclusiveScanNV,
879                   4})},
880             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
881              MakeInstruction(spv::Op::OpGroupIAdd, {1, 2, 3, 7, 4})},
882             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
883              MakeInstruction(
884                  spv::Op::OpGroupIAdd,
885                  {1, 2, 3,
886                   (uint32_t)spv::GroupOperation::PartitionedExclusiveScanNV,
887                   4})},
888             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
889              MakeInstruction(spv::Op::OpGroupIAdd, {1, 2, 3, 8, 4})},
890         })));
891 
892 // SPV_EXT_descriptor_indexing
893 
894 INSTANTIATE_TEST_SUITE_P(
895     SPV_EXT_descriptor_indexing, ExtensionRoundTripTest,
896     Combine(
897         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
898                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,
899                SPV_ENV_VULKAN_1_1),
900         ValuesIn(std::vector<AssemblyCase>{
901             {"OpExtension \"SPV_EXT_descriptor_indexing\"\n",
902              MakeInstruction(spv::Op::OpExtension,
903                              MakeVector("SPV_EXT_descriptor_indexing"))},
904             // Check capabilities, by name
905             {"OpCapability ShaderNonUniform\n",
906              MakeInstruction(spv::Op::OpCapability,
907                              {(uint32_t)spv::Capability::ShaderNonUniformEXT})},
908             {"OpCapability RuntimeDescriptorArray\n",
909              MakeInstruction(
910                  spv::Op::OpCapability,
911                  {(uint32_t)spv::Capability::RuntimeDescriptorArrayEXT})},
912             {"OpCapability InputAttachmentArrayDynamicIndexing\n",
913              MakeInstruction(spv::Op::OpCapability,
914                              {(uint32_t)spv::Capability::
915                                   InputAttachmentArrayDynamicIndexingEXT})},
916             {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
917              MakeInstruction(spv::Op::OpCapability,
918                              {(uint32_t)spv::Capability::
919                                   UniformTexelBufferArrayDynamicIndexingEXT})},
920             {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
921              MakeInstruction(spv::Op::OpCapability,
922                              {(uint32_t)spv::Capability::
923                                   StorageTexelBufferArrayDynamicIndexingEXT})},
924             {"OpCapability UniformBufferArrayNonUniformIndexing\n",
925              MakeInstruction(spv::Op::OpCapability,
926                              {(uint32_t)spv::Capability::
927                                   UniformBufferArrayNonUniformIndexingEXT})},
928             {"OpCapability SampledImageArrayNonUniformIndexing\n",
929              MakeInstruction(spv::Op::OpCapability,
930                              {(uint32_t)spv::Capability::
931                                   SampledImageArrayNonUniformIndexingEXT})},
932             {"OpCapability StorageBufferArrayNonUniformIndexing\n",
933              MakeInstruction(spv::Op::OpCapability,
934                              {(uint32_t)spv::Capability::
935                                   StorageBufferArrayNonUniformIndexingEXT})},
936             {"OpCapability StorageImageArrayNonUniformIndexing\n",
937              MakeInstruction(spv::Op::OpCapability,
938                              {(uint32_t)spv::Capability::
939                                   StorageImageArrayNonUniformIndexingEXT})},
940             {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
941              MakeInstruction(spv::Op::OpCapability,
942                              {(uint32_t)spv::Capability::
943                                   InputAttachmentArrayNonUniformIndexingEXT})},
944             {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
945              MakeInstruction(
946                  spv::Op::OpCapability,
947                  {(uint32_t)spv::Capability::
948                       UniformTexelBufferArrayNonUniformIndexingEXT})},
949             {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
950              MakeInstruction(
951                  spv::Op::OpCapability,
952                  {(uint32_t)spv::Capability::
953                       StorageTexelBufferArrayNonUniformIndexingEXT})},
954             // Check capabilities, by number
955             {"OpCapability ShaderNonUniform\n",
956              MakeInstruction(spv::Op::OpCapability, {5301})},
957             {"OpCapability RuntimeDescriptorArray\n",
958              MakeInstruction(spv::Op::OpCapability, {5302})},
959             {"OpCapability InputAttachmentArrayDynamicIndexing\n",
960              MakeInstruction(spv::Op::OpCapability, {5303})},
961             {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
962              MakeInstruction(spv::Op::OpCapability, {5304})},
963             {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
964              MakeInstruction(spv::Op::OpCapability, {5305})},
965             {"OpCapability UniformBufferArrayNonUniformIndexing\n",
966              MakeInstruction(spv::Op::OpCapability, {5306})},
967             {"OpCapability SampledImageArrayNonUniformIndexing\n",
968              MakeInstruction(spv::Op::OpCapability, {5307})},
969             {"OpCapability StorageBufferArrayNonUniformIndexing\n",
970              MakeInstruction(spv::Op::OpCapability, {5308})},
971             {"OpCapability StorageImageArrayNonUniformIndexing\n",
972              MakeInstruction(spv::Op::OpCapability, {5309})},
973             {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
974              MakeInstruction(spv::Op::OpCapability, {5310})},
975             {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
976              MakeInstruction(spv::Op::OpCapability, {5311})},
977             {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
978              MakeInstruction(spv::Op::OpCapability, {5312})},
979 
980             // Check the decoration token
981             {"OpDecorate %1 NonUniform\n",
982              MakeInstruction(spv::Op::OpDecorate,
983                              {1, (uint32_t)spv::Decoration::NonUniformEXT})},
984             {"OpDecorate %1 NonUniform\n",
985              MakeInstruction(spv::Op::OpDecorate, {1, 5300})},
986         })));
987 
988 // SPV_KHR_linkonce_odr
989 
990 INSTANTIATE_TEST_SUITE_P(
991     SPV_KHR_linkonce_odr, ExtensionRoundTripTest,
992     Combine(
993         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,
994                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
995         ValuesIn(std::vector<AssemblyCase>{
996             {"OpExtension \"SPV_KHR_linkonce_odr\"\n",
997              MakeInstruction(spv::Op::OpExtension,
998                              MakeVector("SPV_KHR_linkonce_odr"))},
999             {"OpDecorate %1 LinkageAttributes \"foobar\" LinkOnceODR\n",
1000              MakeInstruction(
1001                  spv::Op::OpDecorate,
1002                  Concatenate({{1, (uint32_t)spv::Decoration::LinkageAttributes},
1003                               MakeVector("foobar"),
1004                               {(uint32_t)spv::LinkageType::LinkOnceODR}}))},
1005         })));
1006 
1007 // SPV_KHR_expect_assume
1008 
1009 INSTANTIATE_TEST_SUITE_P(
1010     SPV_KHR_expect_assume, ExtensionRoundTripTest,
1011     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3,
1012                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
1013             ValuesIn(std::vector<AssemblyCase>{
1014                 {"OpExtension \"SPV_KHR_expect_assume\"\n",
1015                  MakeInstruction(spv::Op::OpExtension,
1016                                  MakeVector("SPV_KHR_expect_assume"))},
1017                 {"OpAssumeTrueKHR %1\n",
1018                  MakeInstruction(spv::Op::OpAssumeTrueKHR, {1})}})));
1019 // SPV_KHR_subgroup_uniform_control_flow
1020 
1021 INSTANTIATE_TEST_SUITE_P(
1022     SPV_KHR_subgroup_uniform_control_flow, ExtensionRoundTripTest,
1023     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3,
1024                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
1025             ValuesIn(std::vector<AssemblyCase>{
1026                 {"OpExtension \"SPV_KHR_subgroup_uniform_control_flow\"\n",
1027                  MakeInstruction(
1028                      spv::Op::OpExtension,
1029                      MakeVector("SPV_KHR_subgroup_uniform_control_flow"))},
1030                 {"OpExecutionMode %1 SubgroupUniformControlFlowKHR\n",
1031                  MakeInstruction(spv::Op::OpExecutionMode,
1032                                  {1, (uint32_t)spv::ExecutionMode::
1033                                          SubgroupUniformControlFlowKHR})},
1034             })));
1035 
1036 // SPV_KHR_integer_dot_product
1037 
1038 INSTANTIATE_TEST_SUITE_P(
1039     SPV_KHR_integer_dot_product, ExtensionRoundTripTest,
1040     Combine(
1041         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5,
1042                SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1,
1043                SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
1044         ValuesIn(std::vector<AssemblyCase>{
1045             {"OpExtension \"SPV_KHR_integer_dot_product\"\n",
1046              MakeInstruction(spv::Op::OpExtension,
1047                              MakeVector("SPV_KHR_integer_dot_product"))},
1048             {"OpCapability DotProductInputAll\n",
1049              MakeInstruction(
1050                  spv::Op::OpCapability,
1051                  {(uint32_t)spv::Capability::DotProductInputAllKHR})},
1052             {"OpCapability DotProductInput4x8Bit\n",
1053              MakeInstruction(
1054                  spv::Op::OpCapability,
1055                  {(uint32_t)spv::Capability::DotProductInput4x8BitKHR})},
1056             {"OpCapability DotProductInput4x8BitPacked\n",
1057              MakeInstruction(
1058                  spv::Op::OpCapability,
1059                  {(uint32_t)spv::Capability::DotProductInput4x8BitPackedKHR})},
1060             {"OpCapability DotProduct\n",
1061              MakeInstruction(spv::Op::OpCapability,
1062                              {(uint32_t)spv::Capability::DotProductKHR})},
1063             {"%2 = OpSDot %1 %3 %4\n",
1064              MakeInstruction(spv::Op::OpSDotKHR, {1, 2, 3, 4})},
1065             {"%2 = OpSDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
1066              MakeInstruction(
1067                  spv::Op::OpSDotKHR,
1068                  {1, 2, 3, 4,
1069                   (uint32_t)
1070                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1071             {"%2 = OpUDot %1 %3 %4\n",
1072              MakeInstruction(spv::Op::OpUDotKHR, {1, 2, 3, 4})},
1073             {"%2 = OpUDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
1074              MakeInstruction(
1075                  spv::Op::OpUDotKHR,
1076                  {1, 2, 3, 4,
1077                   (uint32_t)
1078                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1079             {"%2 = OpSUDot %1 %3 %4\n",
1080              MakeInstruction(spv::Op::OpSUDotKHR, {1, 2, 3, 4})},
1081             {"%2 = OpSUDot %1 %3 %4 PackedVectorFormat4x8Bit\n",
1082              MakeInstruction(
1083                  spv::Op::OpSUDotKHR,
1084                  {1, 2, 3, 4,
1085                   (uint32_t)
1086                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1087             {"%2 = OpSDotAccSat %1 %3 %4 %5\n",
1088              MakeInstruction(spv::Op::OpSDotAccSatKHR, {1, 2, 3, 4, 5})},
1089             {"%2 = OpSDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
1090              MakeInstruction(
1091                  spv::Op::OpSDotAccSatKHR,
1092                  {1, 2, 3, 4, 5,
1093                   (uint32_t)
1094                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1095             {"%2 = OpUDotAccSat %1 %3 %4 %5\n",
1096              MakeInstruction(spv::Op::OpUDotAccSatKHR, {1, 2, 3, 4, 5})},
1097             {"%2 = OpUDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
1098              MakeInstruction(
1099                  spv::Op::OpUDotAccSatKHR,
1100                  {1, 2, 3, 4, 5,
1101                   (uint32_t)
1102                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1103             {"%2 = OpSUDotAccSat %1 %3 %4 %5\n",
1104              MakeInstruction(spv::Op::OpSUDotAccSatKHR, {1, 2, 3, 4, 5})},
1105             {"%2 = OpSUDotAccSat %1 %3 %4 %5 PackedVectorFormat4x8Bit\n",
1106              MakeInstruction(
1107                  spv::Op::OpSUDotAccSatKHR,
1108                  {1, 2, 3, 4, 5,
1109                   (uint32_t)
1110                       spv::PackedVectorFormat::PackedVectorFormat4x8BitKHR})},
1111         })));
1112 
1113 // SPV_KHR_bit_instructions
1114 
1115 INSTANTIATE_TEST_SUITE_P(
1116     SPV_KHR_bit_instructions, ExtensionRoundTripTest,
1117     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5,
1118                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
1119             ValuesIn(std::vector<AssemblyCase>{
1120                 {"OpExtension \"SPV_KHR_bit_instructions\"\n",
1121                  MakeInstruction(spv::Op::OpExtension,
1122                                  MakeVector("SPV_KHR_bit_instructions"))},
1123                 {"OpCapability BitInstructions\n",
1124                  MakeInstruction(spv::Op::OpCapability,
1125                                  {(uint32_t)spv::Capability::BitInstructions})},
1126             })));
1127 
1128 // SPV_KHR_uniform_group_instructions
1129 
1130 INSTANTIATE_TEST_SUITE_P(
1131     SPV_KHR_uniform_group_instructions, ExtensionRoundTripTest,
1132     Combine(
1133         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5,
1134                SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1,
1135                SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
1136         ValuesIn(std::vector<AssemblyCase>{
1137             {"OpExtension \"SPV_KHR_uniform_group_instructions\"\n",
1138              MakeInstruction(spv::Op::OpExtension,
1139                              MakeVector("SPV_KHR_uniform_group_instructions"))},
1140             {"OpCapability GroupUniformArithmeticKHR\n",
1141              MakeInstruction(
1142                  spv::Op::OpCapability,
1143                  {(uint32_t)spv::Capability::GroupUniformArithmeticKHR})},
1144             {"%2 = OpGroupIMulKHR %1 %3 Reduce %4\n",
1145              MakeInstruction(spv::Op::OpGroupIMulKHR,
1146                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1147                               4})},
1148             {"%2 = OpGroupFMulKHR %1 %3 Reduce %4\n",
1149              MakeInstruction(spv::Op::OpGroupFMulKHR,
1150                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1151                               4})},
1152             {"%2 = OpGroupBitwiseAndKHR %1 %3 Reduce %4\n",
1153              MakeInstruction(spv::Op::OpGroupBitwiseAndKHR,
1154                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1155                               4})},
1156             {"%2 = OpGroupBitwiseOrKHR %1 %3 Reduce %4\n",
1157              MakeInstruction(spv::Op::OpGroupBitwiseOrKHR,
1158                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1159                               4})},
1160             {"%2 = OpGroupBitwiseXorKHR %1 %3 Reduce %4\n",
1161              MakeInstruction(spv::Op::OpGroupBitwiseXorKHR,
1162                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1163                               4})},
1164             {"%2 = OpGroupLogicalAndKHR %1 %3 Reduce %4\n",
1165              MakeInstruction(spv::Op::OpGroupLogicalAndKHR,
1166                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1167                               4})},
1168             {"%2 = OpGroupLogicalOrKHR %1 %3 Reduce %4\n",
1169              MakeInstruction(spv::Op::OpGroupLogicalOrKHR,
1170                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1171                               4})},
1172             {"%2 = OpGroupLogicalXorKHR %1 %3 Reduce %4\n",
1173              MakeInstruction(spv::Op::OpGroupLogicalXorKHR,
1174                              {1, 2, 3, (uint32_t)spv::GroupOperation::Reduce,
1175                               4})},
1176         })));
1177 
1178 // SPV_KHR_subgroup_rotate
1179 
1180 INSTANTIATE_TEST_SUITE_P(
1181     SPV_KHR_subgroup_rotate, ExtensionRoundTripTest,
1182     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6,
1183                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2,
1184                    SPV_ENV_VULKAN_1_3, SPV_ENV_OPENCL_2_1),
1185             ValuesIn(std::vector<AssemblyCase>{
1186                 {"OpExtension \"SPV_KHR_subgroup_rotate\"\n",
1187                  MakeInstruction(spv::Op::OpExtension,
1188                                  MakeVector("SPV_KHR_subgroup_rotate"))},
1189                 {"OpCapability GroupNonUniformRotateKHR\n",
1190                  MakeInstruction(
1191                      spv::Op::OpCapability,
1192                      {(uint32_t)spv::Capability::GroupNonUniformRotateKHR})},
1193                 {"%2 = OpGroupNonUniformRotateKHR %1 %3 %4 %5\n",
1194                  MakeInstruction(spv::Op::OpGroupNonUniformRotateKHR,
1195                                  {1, 2, 3, 4, 5})},
1196                 {"%2 = OpGroupNonUniformRotateKHR %1 %3 %4 %5 %6\n",
1197                  MakeInstruction(spv::Op::OpGroupNonUniformRotateKHR,
1198                                  {1, 2, 3, 4, 5, 6})},
1199             })));
1200 
1201 // SPV_EXT_shader_tile_image
1202 
1203 INSTANTIATE_TEST_SUITE_P(
1204     SPV_EXT_shader_tile_image, ExtensionRoundTripTest,
1205     Combine(
1206         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
1207                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
1208         ValuesIn(std::vector<AssemblyCase>{
1209             {"OpExtension \"SPV_EXT_shader_tile_image\"\n",
1210              MakeInstruction(spv::Op::OpExtension,
1211                              MakeVector("SPV_EXT_shader_tile_image"))},
1212             {"OpCapability TileImageColorReadAccessEXT\n",
1213              MakeInstruction(
1214                  spv::Op::OpCapability,
1215                  {(uint32_t)spv::Capability::TileImageColorReadAccessEXT})},
1216             {"OpCapability TileImageDepthReadAccessEXT\n",
1217              MakeInstruction(
1218                  spv::Op::OpCapability,
1219                  {(uint32_t)spv::Capability::TileImageDepthReadAccessEXT})},
1220             {"OpCapability TileImageStencilReadAccessEXT\n",
1221              MakeInstruction(
1222                  spv::Op::OpCapability,
1223                  {(uint32_t)spv::Capability::TileImageStencilReadAccessEXT})},
1224             {"OpExecutionMode %1 NonCoherentColorAttachmentReadEXT\n",
1225              MakeInstruction(spv::Op::OpExecutionMode,
1226                              {1, (uint32_t)spv::ExecutionMode::
1227                                      NonCoherentColorAttachmentReadEXT})},
1228             {"OpExecutionMode %1 NonCoherentDepthAttachmentReadEXT\n",
1229              MakeInstruction(spv::Op::OpExecutionMode,
1230                              {1, (uint32_t)spv::ExecutionMode::
1231                                      NonCoherentDepthAttachmentReadEXT})},
1232             {"OpExecutionMode %1 NonCoherentStencilAttachmentReadEXT\n",
1233              MakeInstruction(spv::Op::OpExecutionMode,
1234                              {1, (uint32_t)spv::ExecutionMode::
1235                                      NonCoherentStencilAttachmentReadEXT})},
1236             {"%2 = OpColorAttachmentReadEXT %1 %3\n",
1237              MakeInstruction(spv::Op::OpColorAttachmentReadEXT, {1, 2, 3})},
1238             {"%2 = OpColorAttachmentReadEXT %1 %3 %4\n",
1239              MakeInstruction(spv::Op::OpColorAttachmentReadEXT, {1, 2, 3, 4})},
1240             {"%2 = OpDepthAttachmentReadEXT %1\n",
1241              MakeInstruction(spv::Op::OpDepthAttachmentReadEXT, {1, 2})},
1242             {"%2 = OpDepthAttachmentReadEXT %1 %3\n",
1243              MakeInstruction(spv::Op::OpDepthAttachmentReadEXT, {1, 2, 3})},
1244             {"%2 = OpStencilAttachmentReadEXT %1\n",
1245              MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2})},
1246             {"%2 = OpStencilAttachmentReadEXT %1 %3\n",
1247              MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2, 3})},
1248         })));
1249 
1250 // SPV_KHR_maximal_reconvergence
1251 
1252 INSTANTIATE_TEST_SUITE_P(
1253     SPV_KHR_maximal_reconvergence, ExtensionRoundTripTest,
1254     Combine(
1255         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
1256                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
1257         ValuesIn(std::vector<AssemblyCase>{
1258             {"OpExtension \"SPV_KHR_maximal_reconvergence\"\n",
1259              MakeInstruction(spv::Op::OpExtension,
1260                              MakeVector("SPV_KHR_maximal_reconvergence"))},
1261             {"OpExecutionMode %1 MaximallyReconvergesKHR\n",
1262              MakeInstruction(
1263                  spv::Op::OpExecutionMode,
1264                  {1, (uint32_t)spv::ExecutionMode::MaximallyReconvergesKHR})},
1265         })));
1266 
1267 // SPV_KHR_float_controls2
1268 
1269 INSTANTIATE_TEST_SUITE_P(
1270     SPV_KHR_float_controls2, ExtensionRoundTripTest,
1271     Combine(
1272         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
1273                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3),
1274         ValuesIn(std::vector<AssemblyCase>{
1275             {"OpExtension \"SPV_KHR_float_controls2\"\n",
1276              MakeInstruction(spv::Op::OpExtension,
1277                              MakeVector("SPV_KHR_float_controls2"))},
1278             {"OpCapability FloatControls2\n",
1279              MakeInstruction(spv::Op::OpCapability,
1280                              {(uint32_t)spv::Capability::FloatControls2})},
1281             {"OpExecutionMode %1 FPFastMathDefault %2 %3\n",
1282              // The operands are: target type, flags constant
1283              MakeInstruction(
1284                  spv::Op::OpExecutionMode,
1285                  {1, (uint32_t)spv::ExecutionMode::FPFastMathDefault, 2, 3})},
1286             {"OpDecorate %1 FPFastMathMode AllowContract\n",
1287              MakeInstruction(
1288                  spv::Op::OpDecorate,
1289                  {1, (uint32_t)spv::Decoration::FPFastMathMode,
1290                   (uint32_t)spv::FPFastMathModeMask::AllowContract})},
1291             {"OpDecorate %1 FPFastMathMode AllowReassoc\n",
1292              MakeInstruction(
1293                  spv::Op::OpDecorate,
1294                  {1, (uint32_t)spv::Decoration::FPFastMathMode,
1295                   (uint32_t)spv::FPFastMathModeMask::AllowReassoc})},
1296             {"OpDecorate %1 FPFastMathMode AllowTransform\n",
1297              MakeInstruction(
1298                  spv::Op::OpDecorate,
1299                  {1, (uint32_t)spv::Decoration::FPFastMathMode,
1300                   (uint32_t)spv::FPFastMathModeMask::AllowTransform})},
1301         })));
1302 
1303 }  // namespace
1304 }  // namespace spvtools
1305