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(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
91           MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
92           MakeInstruction(
93               SpvOpExtInst,
94               {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
95           MakeInstruction(SpvOpExtInst,
96                           {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
97       })));
98 
99   // Make sure it disassembles correctly.
100   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
101 }
102 
103 // A test case for assembling into words in an instruction.
104 struct AssemblyCase {
105   std::string input;
106   std::vector<uint32_t> expected;
107 };
108 
109 using ExtensionAssemblyTest = spvtest::TextToBinaryTestBase<
110     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
111 
112 TEST_P(ExtensionAssemblyTest, Samples) {
113   const spv_target_env& env = std::get<0>(GetParam());
114   const AssemblyCase& ac = std::get<1>(GetParam());
115 
116   // Check that it assembles correctly.
117   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
118 }
119 
120 using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
121     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
122 
123 TEST_P(ExtensionRoundTripTest, Samples) {
124   const spv_target_env& env = std::get<0>(GetParam());
125   const AssemblyCase& ac = std::get<1>(GetParam());
126 
127   // Check that it assembles correctly.
128   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
129 
130   // Check round trip through the disassembler.
131   EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
132                                           SPV_BINARY_TO_TEXT_OPTION_NONE, env),
133               Eq(ac.input))
134       << "target env: " << spvTargetEnvDescription(env) << "\n";
135 }
136 
137 // SPV_KHR_shader_ballot
138 
139 INSTANTIATE_TEST_SUITE_P(
140     SPV_KHR_shader_ballot, ExtensionRoundTripTest,
141     // We'll get coverage over operand tables by trying the universal
142     // environments, and at least one specific environment.
143     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
144                    SPV_ENV_VULKAN_1_0),
145             ValuesIn(std::vector<AssemblyCase>{
146                 {"OpCapability SubgroupBallotKHR\n",
147                  MakeInstruction(SpvOpCapability,
148                                  {SpvCapabilitySubgroupBallotKHR})},
149                 {"%2 = OpSubgroupBallotKHR %1 %3\n",
150                  MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
151                 {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
152                  MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
153                 {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
154                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
155                                                  SpvBuiltInSubgroupEqMaskKHR})},
156                 {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
157                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
158                                                  SpvBuiltInSubgroupGeMaskKHR})},
159                 {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
160                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
161                                                  SpvBuiltInSubgroupGtMaskKHR})},
162                 {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
163                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
164                                                  SpvBuiltInSubgroupLeMaskKHR})},
165                 {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
166                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
167                                                  SpvBuiltInSubgroupLtMaskKHR})},
168             })));
169 
170 INSTANTIATE_TEST_SUITE_P(
171     SPV_KHR_shader_ballot_vulkan_1_1, ExtensionRoundTripTest,
172     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
173     // builtin enums.
174     Combine(Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
175             ValuesIn(std::vector<AssemblyCase>{
176                 {"OpCapability SubgroupBallotKHR\n",
177                  MakeInstruction(SpvOpCapability,
178                                  {SpvCapabilitySubgroupBallotKHR})},
179                 {"%2 = OpSubgroupBallotKHR %1 %3\n",
180                  MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
181                 {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
182                  MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
183                 {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
184                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
185                                                  SpvBuiltInSubgroupEqMask})},
186                 {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
187                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
188                                                  SpvBuiltInSubgroupGeMask})},
189                 {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
190                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
191                                                  SpvBuiltInSubgroupGtMask})},
192                 {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
193                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
194                                                  SpvBuiltInSubgroupLeMask})},
195                 {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
196                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
197                                                  SpvBuiltInSubgroupLtMask})},
198             })));
199 
200 // The old builtin names (with KHR suffix) still work in the assmebler, and
201 // map to the enums without the KHR.
202 INSTANTIATE_TEST_SUITE_P(
203     SPV_KHR_shader_ballot_vulkan_1_1_alias_check, ExtensionAssemblyTest,
204     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
205     // builtin enums.
206     Combine(Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
207             ValuesIn(std::vector<AssemblyCase>{
208                 {"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
209                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
210                                                  SpvBuiltInSubgroupEqMask})},
211                 {"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
212                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
213                                                  SpvBuiltInSubgroupGeMask})},
214                 {"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
215                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
216                                                  SpvBuiltInSubgroupGtMask})},
217                 {"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
218                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
219                                                  SpvBuiltInSubgroupLeMask})},
220                 {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
221                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
222                                                  SpvBuiltInSubgroupLtMask})},
223             })));
224 
225 // SPV_KHR_shader_draw_parameters
226 
227 INSTANTIATE_TEST_SUITE_P(
228     SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest,
229     // We'll get coverage over operand tables by trying the universal
230     // environments, and at least one specific environment.
231     Combine(
232         ValuesIn(CommonVulkanEnvs()),
233         ValuesIn(std::vector<AssemblyCase>{
234             {"OpCapability DrawParameters\n",
235              MakeInstruction(SpvOpCapability, {SpvCapabilityDrawParameters})},
236             {"OpDecorate %1 BuiltIn BaseVertex\n",
237              MakeInstruction(SpvOpDecorate,
238                              {1, SpvDecorationBuiltIn, SpvBuiltInBaseVertex})},
239             {"OpDecorate %1 BuiltIn BaseInstance\n",
240              MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
241                                              SpvBuiltInBaseInstance})},
242             {"OpDecorate %1 BuiltIn DrawIndex\n",
243              MakeInstruction(SpvOpDecorate,
244                              {1, SpvDecorationBuiltIn, SpvBuiltInDrawIndex})},
245         })));
246 
247 // SPV_KHR_subgroup_vote
248 
249 INSTANTIATE_TEST_SUITE_P(
250     SPV_KHR_subgroup_vote, ExtensionRoundTripTest,
251     // We'll get coverage over operand tables by trying the universal
252     // environments, and at least one specific environment.
253     Combine(ValuesIn(CommonVulkanEnvs()),
254             ValuesIn(std::vector<AssemblyCase>{
255                 {"OpCapability SubgroupVoteKHR\n",
256                  MakeInstruction(SpvOpCapability,
257                                  {SpvCapabilitySubgroupVoteKHR})},
258                 {"%2 = OpSubgroupAnyKHR %1 %3\n",
259                  MakeInstruction(SpvOpSubgroupAnyKHR, {1, 2, 3})},
260                 {"%2 = OpSubgroupAllKHR %1 %3\n",
261                  MakeInstruction(SpvOpSubgroupAllKHR, {1, 2, 3})},
262                 {"%2 = OpSubgroupAllEqualKHR %1 %3\n",
263                  MakeInstruction(SpvOpSubgroupAllEqualKHR, {1, 2, 3})},
264             })));
265 
266 // SPV_KHR_16bit_storage
267 
268 INSTANTIATE_TEST_SUITE_P(
269     SPV_KHR_16bit_storage, ExtensionRoundTripTest,
270     // We'll get coverage over operand tables by trying the universal
271     // environments, and at least one specific environment.
272     Combine(ValuesIn(CommonVulkanEnvs()),
273             ValuesIn(std::vector<AssemblyCase>{
274                 {"OpCapability StorageBuffer16BitAccess\n",
275                  MakeInstruction(SpvOpCapability,
276                                  {SpvCapabilityStorageUniformBufferBlock16})},
277                 {"OpCapability StorageBuffer16BitAccess\n",
278                  MakeInstruction(SpvOpCapability,
279                                  {SpvCapabilityStorageBuffer16BitAccess})},
280                 {"OpCapability UniformAndStorageBuffer16BitAccess\n",
281                  MakeInstruction(
282                      SpvOpCapability,
283                      {SpvCapabilityUniformAndStorageBuffer16BitAccess})},
284                 {"OpCapability UniformAndStorageBuffer16BitAccess\n",
285                  MakeInstruction(SpvOpCapability,
286                                  {SpvCapabilityStorageUniform16})},
287                 {"OpCapability StoragePushConstant16\n",
288                  MakeInstruction(SpvOpCapability,
289                                  {SpvCapabilityStoragePushConstant16})},
290                 {"OpCapability StorageInputOutput16\n",
291                  MakeInstruction(SpvOpCapability,
292                                  {SpvCapabilityStorageInputOutput16})},
293             })));
294 
295 INSTANTIATE_TEST_SUITE_P(
296     SPV_KHR_16bit_storage_alias_check, ExtensionAssemblyTest,
297     Combine(ValuesIn(CommonVulkanEnvs()),
298             ValuesIn(std::vector<AssemblyCase>{
299                 // The old name maps to the new enum.
300                 {"OpCapability StorageUniformBufferBlock16\n",
301                  MakeInstruction(SpvOpCapability,
302                                  {SpvCapabilityStorageBuffer16BitAccess})},
303                 // The new name maps to the old enum.
304                 {"OpCapability UniformAndStorageBuffer16BitAccess\n",
305                  MakeInstruction(SpvOpCapability,
306                                  {SpvCapabilityStorageUniform16})},
307             })));
308 
309 // SPV_KHR_device_group
310 
311 INSTANTIATE_TEST_SUITE_P(
312     SPV_KHR_device_group, ExtensionRoundTripTest,
313     // We'll get coverage over operand tables by trying the universal
314     // environments, and at least one specific environment.
315     Combine(ValuesIn(CommonVulkanEnvs()),
316             ValuesIn(std::vector<AssemblyCase>{
317                 {"OpCapability DeviceGroup\n",
318                  MakeInstruction(SpvOpCapability, {SpvCapabilityDeviceGroup})},
319                 {"OpDecorate %1 BuiltIn DeviceIndex\n",
320                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
321                                                  SpvBuiltInDeviceIndex})},
322             })));
323 
324 // SPV_KHR_8bit_storage
325 
326 INSTANTIATE_TEST_SUITE_P(
327     SPV_KHR_8bit_storage, ExtensionRoundTripTest,
328     // We'll get coverage over operand tables by trying the universal
329     // environments, and at least one specific environment.
330     Combine(
331         ValuesIn(CommonVulkanEnvs()),
332         ValuesIn(std::vector<AssemblyCase>{
333             {"OpCapability StorageBuffer8BitAccess\n",
334              MakeInstruction(SpvOpCapability,
335                              {SpvCapabilityStorageBuffer8BitAccess})},
336             {"OpCapability UniformAndStorageBuffer8BitAccess\n",
337              MakeInstruction(SpvOpCapability,
338                              {SpvCapabilityUniformAndStorageBuffer8BitAccess})},
339             {"OpCapability StoragePushConstant8\n",
340              MakeInstruction(SpvOpCapability,
341                              {SpvCapabilityStoragePushConstant8})},
342         })));
343 
344 // SPV_KHR_multiview
345 
346 INSTANTIATE_TEST_SUITE_P(
347     SPV_KHR_multiview, ExtensionRoundTripTest,
348     // We'll get coverage over operand tables by trying the universal
349     // environments, and at least one specific environment.
350     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
351                    SPV_ENV_VULKAN_1_0),
352             ValuesIn(std::vector<AssemblyCase>{
353                 {"OpCapability MultiView\n",
354                  MakeInstruction(SpvOpCapability, {SpvCapabilityMultiView})},
355                 {"OpDecorate %1 BuiltIn ViewIndex\n",
356                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
357                                                  SpvBuiltInViewIndex})},
358             })));
359 
360 // SPV_AMD_shader_explicit_vertex_parameter
361 
362 #define PREAMBLE \
363   "%1 = OpExtInstImport \"SPV_AMD_shader_explicit_vertex_parameter\"\n"
364 INSTANTIATE_TEST_SUITE_P(
365     SPV_AMD_shader_explicit_vertex_parameter, ExtensionRoundTripTest,
366     // We'll get coverage over operand tables by trying the universal
367     // environments, and at least one specific environment.
368     Combine(
369         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
370                SPV_ENV_VULKAN_1_0),
371         ValuesIn(std::vector<AssemblyCase>{
372             {PREAMBLE "%3 = OpExtInst %2 %1 InterpolateAtVertexAMD %4 %5\n",
373              Concatenate(
374                  {MakeInstruction(
375                       SpvOpExtInstImport, {1},
376                       MakeVector("SPV_AMD_shader_explicit_vertex_parameter")),
377                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5})})},
378         })));
379 #undef PREAMBLE
380 
381 // SPV_AMD_shader_trinary_minmax
382 
383 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_trinary_minmax\"\n"
384 INSTANTIATE_TEST_SUITE_P(
385     SPV_AMD_shader_trinary_minmax, ExtensionRoundTripTest,
386     // We'll get coverage over operand tables by trying the universal
387     // environments, and at least one specific environment.
388     Combine(
389         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
390                SPV_ENV_VULKAN_1_0),
391         ValuesIn(std::vector<AssemblyCase>{
392             {PREAMBLE "%3 = OpExtInst %2 %1 FMin3AMD %4 %5 %6\n",
393              Concatenate(
394                  {MakeInstruction(SpvOpExtInstImport, {1},
395                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
396                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5, 6})})},
397             {PREAMBLE "%3 = OpExtInst %2 %1 UMin3AMD %4 %5 %6\n",
398              Concatenate(
399                  {MakeInstruction(SpvOpExtInstImport, {1},
400                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
401                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4, 5, 6})})},
402             {PREAMBLE "%3 = OpExtInst %2 %1 SMin3AMD %4 %5 %6\n",
403              Concatenate(
404                  {MakeInstruction(SpvOpExtInstImport, {1},
405                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
406                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 3, 4, 5, 6})})},
407             {PREAMBLE "%3 = OpExtInst %2 %1 FMax3AMD %4 %5 %6\n",
408              Concatenate(
409                  {MakeInstruction(SpvOpExtInstImport, {1},
410                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
411                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 4, 4, 5, 6})})},
412             {PREAMBLE "%3 = OpExtInst %2 %1 UMax3AMD %4 %5 %6\n",
413              Concatenate(
414                  {MakeInstruction(SpvOpExtInstImport, {1},
415                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
416                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 5, 4, 5, 6})})},
417             {PREAMBLE "%3 = OpExtInst %2 %1 SMax3AMD %4 %5 %6\n",
418              Concatenate(
419                  {MakeInstruction(SpvOpExtInstImport, {1},
420                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
421                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 6, 4, 5, 6})})},
422             {PREAMBLE "%3 = OpExtInst %2 %1 FMid3AMD %4 %5 %6\n",
423              Concatenate(
424                  {MakeInstruction(SpvOpExtInstImport, {1},
425                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
426                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 7, 4, 5, 6})})},
427             {PREAMBLE "%3 = OpExtInst %2 %1 UMid3AMD %4 %5 %6\n",
428              Concatenate(
429                  {MakeInstruction(SpvOpExtInstImport, {1},
430                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
431                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 8, 4, 5, 6})})},
432             {PREAMBLE "%3 = OpExtInst %2 %1 SMid3AMD %4 %5 %6\n",
433              Concatenate(
434                  {MakeInstruction(SpvOpExtInstImport, {1},
435                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
436                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 9, 4, 5, 6})})},
437         })));
438 #undef PREAMBLE
439 
440 // SPV_AMD_gcn_shader
441 
442 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
443 INSTANTIATE_TEST_SUITE_P(
444     SPV_AMD_gcn_shader, ExtensionRoundTripTest,
445     // We'll get coverage over operand tables by trying the universal
446     // environments, and at least one specific environment.
447     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
448                    SPV_ENV_VULKAN_1_0),
449             ValuesIn(std::vector<AssemblyCase>{
450                 {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
451                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
452                                               MakeVector("SPV_AMD_gcn_shader")),
453                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4})})},
454                 {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
455                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
456                                               MakeVector("SPV_AMD_gcn_shader")),
457                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4})})},
458                 {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
459                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
460                                               MakeVector("SPV_AMD_gcn_shader")),
461                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})},
462             })));
463 #undef PREAMBLE
464 
465 // SPV_AMD_shader_ballot
466 
467 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_ballot\"\n"
468 INSTANTIATE_TEST_SUITE_P(
469     SPV_AMD_shader_ballot, ExtensionRoundTripTest,
470     // We'll get coverage over operand tables by trying the universal
471     // environments, and at least one specific environment.
472     Combine(
473         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
474                SPV_ENV_VULKAN_1_0),
475         ValuesIn(std::vector<AssemblyCase>{
476             {PREAMBLE "%3 = OpExtInst %2 %1 SwizzleInvocationsAMD %4 %5\n",
477              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
478                                           MakeVector("SPV_AMD_shader_ballot")),
479                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5})})},
480             {PREAMBLE
481              "%3 = OpExtInst %2 %1 SwizzleInvocationsMaskedAMD %4 %5\n",
482              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
483                                           MakeVector("SPV_AMD_shader_ballot")),
484                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4, 5})})},
485             {PREAMBLE "%3 = OpExtInst %2 %1 WriteInvocationAMD %4 %5 %6\n",
486              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
487                                           MakeVector("SPV_AMD_shader_ballot")),
488                           MakeInstruction(SpvOpExtInst,
489                                           {2, 3, 1, 3, 4, 5, 6})})},
490             {PREAMBLE "%3 = OpExtInst %2 %1 MbcntAMD %4\n",
491              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
492                                           MakeVector("SPV_AMD_shader_ballot")),
493                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 4, 4})})},
494         })));
495 #undef PREAMBLE
496 
497 // SPV_KHR_variable_pointers
498 
499 INSTANTIATE_TEST_SUITE_P(
500     SPV_KHR_variable_pointers, ExtensionRoundTripTest,
501     // We'll get coverage over operand tables by trying the universal
502     // environments, and at least one specific environment.
503     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
504                    SPV_ENV_VULKAN_1_0),
505             ValuesIn(std::vector<AssemblyCase>{
506                 {"OpCapability VariablePointers\n",
507                  MakeInstruction(SpvOpCapability,
508                                  {SpvCapabilityVariablePointers})},
509                 {"OpCapability VariablePointersStorageBuffer\n",
510                  MakeInstruction(SpvOpCapability,
511                                  {SpvCapabilityVariablePointersStorageBuffer})},
512             })));
513 
514 // SPV_KHR_vulkan_memory_model
515 
516 INSTANTIATE_TEST_SUITE_P(
517     SPV_KHR_vulkan_memory_model, ExtensionRoundTripTest,
518     // We'll get coverage over operand tables by trying the universal
519     // environments, and at least one specific environment.
520     //
521     // Note: SPV_KHR_vulkan_memory_model adds scope enum value QueueFamilyKHR.
522     // Scope enums are used in ID definitions elsewhere, that don't know they
523     // are using particular enums.  So the assembler doesn't support assembling
524     // those enums names into the corresponding values.  So there is no asm/dis
525     // tests for those enums.
526     Combine(
527         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
528                SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
529         ValuesIn(std::vector<AssemblyCase>{
530             {"OpCapability VulkanMemoryModel\n",
531              MakeInstruction(SpvOpCapability,
532                              {SpvCapabilityVulkanMemoryModelKHR})},
533             {"OpCapability VulkanMemoryModelDeviceScope\n",
534              MakeInstruction(SpvOpCapability,
535                              {SpvCapabilityVulkanMemoryModelDeviceScopeKHR})},
536             {"OpMemoryModel Logical Vulkan\n",
537              MakeInstruction(SpvOpMemoryModel, {SpvAddressingModelLogical,
538                                                 SpvMemoryModelVulkanKHR})},
539             {"OpStore %1 %2 MakePointerAvailable %3\n",
540              MakeInstruction(SpvOpStore,
541                              {1, 2, SpvMemoryAccessMakePointerAvailableKHRMask,
542                               3})},
543             {"OpStore %1 %2 Volatile|MakePointerAvailable %3\n",
544              MakeInstruction(SpvOpStore,
545                              {1, 2,
546                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
547                                   int(SpvMemoryAccessVolatileMask),
548                               3})},
549             {"OpStore %1 %2 Aligned|MakePointerAvailable 4 %3\n",
550              MakeInstruction(SpvOpStore,
551                              {1, 2,
552                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
553                                   int(SpvMemoryAccessAlignedMask),
554                               4, 3})},
555             {"OpStore %1 %2 MakePointerAvailable|NonPrivatePointer %3\n",
556              MakeInstruction(SpvOpStore,
557                              {1, 2,
558                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
559                                   int(SpvMemoryAccessNonPrivatePointerKHRMask),
560                               3})},
561             {"%2 = OpLoad %1 %3 MakePointerVisible %4\n",
562              MakeInstruction(SpvOpLoad,
563                              {1, 2, 3, SpvMemoryAccessMakePointerVisibleKHRMask,
564                               4})},
565             {"%2 = OpLoad %1 %3 Volatile|MakePointerVisible %4\n",
566              MakeInstruction(SpvOpLoad,
567                              {1, 2, 3,
568                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
569                                   int(SpvMemoryAccessVolatileMask),
570                               4})},
571             {"%2 = OpLoad %1 %3 Aligned|MakePointerVisible 8 %4\n",
572              MakeInstruction(SpvOpLoad,
573                              {1, 2, 3,
574                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
575                                   int(SpvMemoryAccessAlignedMask),
576                               8, 4})},
577             {"%2 = OpLoad %1 %3 MakePointerVisible|NonPrivatePointer "
578              "%4\n",
579              MakeInstruction(SpvOpLoad,
580                              {1, 2, 3,
581                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
582                                   int(SpvMemoryAccessNonPrivatePointerKHRMask),
583                               4})},
584             {"OpCopyMemory %1 %2 "
585              "MakePointerAvailable|"
586              "MakePointerVisible|"
587              "NonPrivatePointer "
588              "%3 %4\n",
589              MakeInstruction(SpvOpCopyMemory,
590                              {1, 2,
591                               (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
592                                int(SpvMemoryAccessMakePointerAvailableKHRMask) |
593                                int(SpvMemoryAccessNonPrivatePointerKHRMask)),
594                               3, 4})},
595             {"OpCopyMemorySized %1 %2 %3 "
596              "MakePointerAvailable|"
597              "MakePointerVisible|"
598              "NonPrivatePointer "
599              "%4 %5\n",
600              MakeInstruction(SpvOpCopyMemorySized,
601                              {1, 2, 3,
602                               (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
603                                int(SpvMemoryAccessMakePointerAvailableKHRMask) |
604                                int(SpvMemoryAccessNonPrivatePointerKHRMask)),
605                               4, 5})},
606             // Image operands
607             {"OpImageWrite %1 %2 %3 MakeTexelAvailable "
608              "%4\n",
609              MakeInstruction(
610                  SpvOpImageWrite,
611                  {1, 2, 3, int(SpvImageOperandsMakeTexelAvailableKHRMask), 4})},
612             {"OpImageWrite %1 %2 %3 MakeTexelAvailable|NonPrivateTexel "
613              "%4\n",
614              MakeInstruction(SpvOpImageWrite,
615                              {1, 2, 3,
616                               int(SpvImageOperandsMakeTexelAvailableKHRMask) |
617                                   int(SpvImageOperandsNonPrivateTexelKHRMask),
618                               4})},
619             {"OpImageWrite %1 %2 %3 "
620              "MakeTexelAvailable|NonPrivateTexel|VolatileTexel "
621              "%4\n",
622              MakeInstruction(SpvOpImageWrite,
623                              {1, 2, 3,
624                               int(SpvImageOperandsMakeTexelAvailableKHRMask) |
625                                   int(SpvImageOperandsNonPrivateTexelKHRMask) |
626                                   int(SpvImageOperandsVolatileTexelKHRMask),
627                               4})},
628             {"%2 = OpImageRead %1 %3 %4 MakeTexelVisible "
629              "%5\n",
630              MakeInstruction(SpvOpImageRead,
631                              {1, 2, 3, 4,
632                               int(SpvImageOperandsMakeTexelVisibleKHRMask),
633                               5})},
634             {"%2 = OpImageRead %1 %3 %4 "
635              "MakeTexelVisible|NonPrivateTexel "
636              "%5\n",
637              MakeInstruction(SpvOpImageRead,
638                              {1, 2, 3, 4,
639                               int(SpvImageOperandsMakeTexelVisibleKHRMask) |
640                                   int(SpvImageOperandsNonPrivateTexelKHRMask),
641                               5})},
642             {"%2 = OpImageRead %1 %3 %4 "
643              "MakeTexelVisible|NonPrivateTexel|VolatileTexel "
644              "%5\n",
645              MakeInstruction(SpvOpImageRead,
646                              {1, 2, 3, 4,
647                               int(SpvImageOperandsMakeTexelVisibleKHRMask) |
648                                   int(SpvImageOperandsNonPrivateTexelKHRMask) |
649                                   int(SpvImageOperandsVolatileTexelKHRMask),
650                               5})},
651 
652             // Memory semantics ID values are numbers put into a SPIR-V
653             // constant integer referenced by Id. There is no token for
654             // them, and so no assembler or disassembler support required.
655             // Similar for Scope ID.
656         })));
657 
658 // SPV_GOOGLE_decorate_string
659 
660 // Now that OpDecorateString is the preferred spelling for
661 // OpDecorateStringGOOGLE use that name in round trip tests, and the GOOGLE
662 // name in an assembly-only test.
663 
664 INSTANTIATE_TEST_SUITE_P(
665     SPV_GOOGLE_decorate_string, ExtensionRoundTripTest,
666     Combine(
667         // We'll get coverage over operand tables by trying the universal
668         // environments, and at least one specific environment.
669         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
670                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
671         ValuesIn(std::vector<AssemblyCase>{
672             {"OpDecorateString %1 UserSemantic \"ABC\"\n",
673              MakeInstruction(SpvOpDecorateStringGOOGLE,
674                              {1, SpvDecorationHlslSemanticGOOGLE},
675                              MakeVector("ABC"))},
676             {"OpDecorateString %1 UserSemantic \"ABC\"\n",
677              MakeInstruction(SpvOpDecorateString,
678                              {1, SpvDecorationUserSemantic},
679                              MakeVector("ABC"))},
680             {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n",
681              MakeInstruction(SpvOpMemberDecorateStringGOOGLE,
682                              {1, 3, SpvDecorationUserSemantic},
683                              MakeVector("DEF"))},
684             {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n",
685              MakeInstruction(SpvOpMemberDecorateString,
686                              {1, 3, SpvDecorationUserSemantic},
687                              MakeVector("DEF"))},
688         })));
689 
690 INSTANTIATE_TEST_SUITE_P(
691     SPV_GOOGLE_decorate_string, ExtensionAssemblyTest,
692     Combine(
693         // We'll get coverage over operand tables by trying the universal
694         // environments, and at least one specific environment.
695         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
696                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
697         ValuesIn(std::vector<AssemblyCase>{
698             {"OpDecorateStringGOOGLE %1 HlslSemanticGOOGLE \"ABC\"\n",
699              MakeInstruction(SpvOpDecorateStringGOOGLE,
700                              {1, SpvDecorationHlslSemanticGOOGLE},
701                              MakeVector("ABC"))},
702             {"OpMemberDecorateStringGOOGLE %1 3 HlslSemanticGOOGLE \"DEF\"\n",
703              MakeInstruction(SpvOpMemberDecorateStringGOOGLE,
704                              {1, 3, SpvDecorationHlslSemanticGOOGLE},
705                              MakeVector("DEF"))},
706         })));
707 
708 // SPV_GOOGLE_hlsl_functionality1
709 
710 // Now that CounterBuffer is the preferred spelling for HlslCounterBufferGOOGLE,
711 // use that name in round trip tests, and the GOOGLE name in an assembly-only
712 // test.
713 INSTANTIATE_TEST_SUITE_P(
714     SPV_GOOGLE_hlsl_functionality1, ExtensionRoundTripTest,
715     Combine(
716         // We'll get coverage over operand tables by trying the universal
717         // environments, and at least one specific environment.
718         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
719                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
720         // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since
721         // they are coupled together.
722         ValuesIn(std::vector<AssemblyCase>{
723             {"OpDecorateId %1 CounterBuffer %2\n",
724              MakeInstruction(SpvOpDecorateId,
725                              {1, SpvDecorationHlslCounterBufferGOOGLE, 2})},
726             {"OpDecorateId %1 CounterBuffer %2\n",
727              MakeInstruction(SpvOpDecorateId,
728                              {1, SpvDecorationCounterBuffer, 2})},
729         })));
730 
731 INSTANTIATE_TEST_SUITE_P(
732     SPV_GOOGLE_hlsl_functionality1, ExtensionAssemblyTest,
733     Combine(
734         // We'll get coverage over operand tables by trying the universal
735         // environments, and at least one specific environment.
736         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
737                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
738         // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since
739         // they are coupled together.
740         ValuesIn(std::vector<AssemblyCase>{
741             {"OpDecorateId %1 HlslCounterBufferGOOGLE %2\n",
742              MakeInstruction(SpvOpDecorateId,
743                              {1, SpvDecorationHlslCounterBufferGOOGLE, 2})},
744         })));
745 
746 // SPV_NV_viewport_array2
747 
748 INSTANTIATE_TEST_SUITE_P(
749     SPV_NV_viewport_array2, ExtensionRoundTripTest,
750     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
751                    SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3,
752                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
753             ValuesIn(std::vector<AssemblyCase>{
754                 {"OpExtension \"SPV_NV_viewport_array2\"\n",
755                  MakeInstruction(SpvOpExtension,
756                                  MakeVector("SPV_NV_viewport_array2"))},
757                 // The EXT and NV extensions have the same token number for this
758                 // capability.
759                 {"OpCapability ShaderViewportIndexLayerEXT\n",
760                  MakeInstruction(SpvOpCapability,
761                                  {SpvCapabilityShaderViewportIndexLayerNV})},
762                 // Check the new capability's token number
763                 {"OpCapability ShaderViewportIndexLayerEXT\n",
764                  MakeInstruction(SpvOpCapability, {5254})},
765                 // Decorations
766                 {"OpDecorate %1 ViewportRelativeNV\n",
767                  MakeInstruction(SpvOpDecorate,
768                                  {1, SpvDecorationViewportRelativeNV})},
769                 {"OpDecorate %1 BuiltIn ViewportMaskNV\n",
770                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
771                                                  SpvBuiltInViewportMaskNV})},
772             })));
773 
774 // SPV_NV_shader_subgroup_partitioned
775 
776 INSTANTIATE_TEST_SUITE_P(
777     SPV_NV_shader_subgroup_partitioned, ExtensionRoundTripTest,
778     Combine(
779         Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
780         ValuesIn(std::vector<AssemblyCase>{
781             {"OpExtension \"SPV_NV_shader_subgroup_partitioned\"\n",
782              MakeInstruction(SpvOpExtension,
783                              MakeVector("SPV_NV_shader_subgroup_partitioned"))},
784             {"OpCapability GroupNonUniformPartitionedNV\n",
785              MakeInstruction(SpvOpCapability,
786                              {SpvCapabilityGroupNonUniformPartitionedNV})},
787             // Check the new capability's token number
788             {"OpCapability GroupNonUniformPartitionedNV\n",
789              MakeInstruction(SpvOpCapability, {5297})},
790             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
791              MakeInstruction(SpvOpGroupNonUniformPartitionNV, {1, 2, 3})},
792             // Check the new instruction's token number
793             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
794              MakeInstruction(static_cast<SpvOp>(5296), {1, 2, 3})},
795             // Check the new group operations
796             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
797              MakeInstruction(SpvOpGroupIAdd,
798                              {1, 2, 3, SpvGroupOperationPartitionedReduceNV,
799                               4})},
800             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
801              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 6, 4})},
802             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
803              MakeInstruction(SpvOpGroupIAdd,
804                              {1, 2, 3,
805                               SpvGroupOperationPartitionedInclusiveScanNV, 4})},
806             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
807              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 7, 4})},
808             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
809              MakeInstruction(SpvOpGroupIAdd,
810                              {1, 2, 3,
811                               SpvGroupOperationPartitionedExclusiveScanNV, 4})},
812             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
813              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 8, 4})},
814         })));
815 
816 // SPV_EXT_descriptor_indexing
817 
818 INSTANTIATE_TEST_SUITE_P(
819     SPV_EXT_descriptor_indexing, ExtensionRoundTripTest,
820     Combine(
821         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
822                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,
823                SPV_ENV_VULKAN_1_1),
824         ValuesIn(std::vector<AssemblyCase>{
825             {"OpExtension \"SPV_EXT_descriptor_indexing\"\n",
826              MakeInstruction(SpvOpExtension,
827                              MakeVector("SPV_EXT_descriptor_indexing"))},
828             // Check capabilities, by name
829             {"OpCapability ShaderNonUniform\n",
830              MakeInstruction(SpvOpCapability,
831                              {SpvCapabilityShaderNonUniformEXT})},
832             {"OpCapability RuntimeDescriptorArray\n",
833              MakeInstruction(SpvOpCapability,
834                              {SpvCapabilityRuntimeDescriptorArrayEXT})},
835             {"OpCapability InputAttachmentArrayDynamicIndexing\n",
836              MakeInstruction(
837                  SpvOpCapability,
838                  {SpvCapabilityInputAttachmentArrayDynamicIndexingEXT})},
839             {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
840              MakeInstruction(
841                  SpvOpCapability,
842                  {SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT})},
843             {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
844              MakeInstruction(
845                  SpvOpCapability,
846                  {SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT})},
847             {"OpCapability UniformBufferArrayNonUniformIndexing\n",
848              MakeInstruction(
849                  SpvOpCapability,
850                  {SpvCapabilityUniformBufferArrayNonUniformIndexingEXT})},
851             {"OpCapability SampledImageArrayNonUniformIndexing\n",
852              MakeInstruction(
853                  SpvOpCapability,
854                  {SpvCapabilitySampledImageArrayNonUniformIndexingEXT})},
855             {"OpCapability StorageBufferArrayNonUniformIndexing\n",
856              MakeInstruction(
857                  SpvOpCapability,
858                  {SpvCapabilityStorageBufferArrayNonUniformIndexingEXT})},
859             {"OpCapability StorageImageArrayNonUniformIndexing\n",
860              MakeInstruction(
861                  SpvOpCapability,
862                  {SpvCapabilityStorageImageArrayNonUniformIndexingEXT})},
863             {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
864              MakeInstruction(
865                  SpvOpCapability,
866                  {SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT})},
867             {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
868              MakeInstruction(
869                  SpvOpCapability,
870                  {SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT})},
871             {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
872              MakeInstruction(
873                  SpvOpCapability,
874                  {SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT})},
875             // Check capabilities, by number
876             {"OpCapability ShaderNonUniform\n",
877              MakeInstruction(SpvOpCapability, {5301})},
878             {"OpCapability RuntimeDescriptorArray\n",
879              MakeInstruction(SpvOpCapability, {5302})},
880             {"OpCapability InputAttachmentArrayDynamicIndexing\n",
881              MakeInstruction(SpvOpCapability, {5303})},
882             {"OpCapability UniformTexelBufferArrayDynamicIndexing\n",
883              MakeInstruction(SpvOpCapability, {5304})},
884             {"OpCapability StorageTexelBufferArrayDynamicIndexing\n",
885              MakeInstruction(SpvOpCapability, {5305})},
886             {"OpCapability UniformBufferArrayNonUniformIndexing\n",
887              MakeInstruction(SpvOpCapability, {5306})},
888             {"OpCapability SampledImageArrayNonUniformIndexing\n",
889              MakeInstruction(SpvOpCapability, {5307})},
890             {"OpCapability StorageBufferArrayNonUniformIndexing\n",
891              MakeInstruction(SpvOpCapability, {5308})},
892             {"OpCapability StorageImageArrayNonUniformIndexing\n",
893              MakeInstruction(SpvOpCapability, {5309})},
894             {"OpCapability InputAttachmentArrayNonUniformIndexing\n",
895              MakeInstruction(SpvOpCapability, {5310})},
896             {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n",
897              MakeInstruction(SpvOpCapability, {5311})},
898             {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n",
899              MakeInstruction(SpvOpCapability, {5312})},
900 
901             // Check the decoration token
902             {"OpDecorate %1 NonUniform\n",
903              MakeInstruction(SpvOpDecorate, {1, SpvDecorationNonUniformEXT})},
904             {"OpDecorate %1 NonUniform\n",
905              MakeInstruction(SpvOpDecorate, {1, 5300})},
906         })));
907 
908 // SPV_KHR_linkonce_odr
909 
910 INSTANTIATE_TEST_SUITE_P(
911     SPV_KHR_linkonce_odr, ExtensionRoundTripTest,
912     Combine(
913         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,
914                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
915         ValuesIn(std::vector<AssemblyCase>{
916             {"OpExtension \"SPV_KHR_linkonce_odr\"\n",
917              MakeInstruction(SpvOpExtension,
918                              MakeVector("SPV_KHR_linkonce_odr"))},
919             {"OpDecorate %1 LinkageAttributes \"foobar\" LinkOnceODR\n",
920              MakeInstruction(SpvOpDecorate,
921                              Concatenate({{1, SpvDecorationLinkageAttributes},
922                                           MakeVector("foobar"),
923                                           {SpvLinkageTypeLinkOnceODR}}))},
924         })));
925 
926 // SPV_KHR_expect_assume
927 
928 INSTANTIATE_TEST_SUITE_P(
929     SPV_KHR_expect_assume, ExtensionRoundTripTest,
930     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3,
931                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
932             ValuesIn(std::vector<AssemblyCase>{
933                 {"OpExtension \"SPV_KHR_expect_assume\"\n",
934                  MakeInstruction(SpvOpExtension,
935                                  MakeVector("SPV_KHR_expect_assume"))},
936                 {"OpAssumeTrueKHR %1\n",
937                  MakeInstruction(SpvOpAssumeTrueKHR, {1})}})));
938 // SPV_KHR_subgroup_uniform_control_flow
939 
940 INSTANTIATE_TEST_SUITE_P(
941     SPV_KHR_subgroup_uniform_control_flow, ExtensionRoundTripTest,
942     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3,
943                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
944             ValuesIn(std::vector<AssemblyCase>{
945                 {"OpExtension \"SPV_KHR_subgroup_uniform_control_flow\"\n",
946                  MakeInstruction(
947                      SpvOpExtension,
948                      MakeVector("SPV_KHR_subgroup_uniform_control_flow"))},
949                 {"OpExecutionMode %1 SubgroupUniformControlFlowKHR\n",
950                  MakeInstruction(
951                      SpvOpExecutionMode,
952                      {1, SpvExecutionModeSubgroupUniformControlFlowKHR})},
953             })));
954 
955 // SPV_KHR_integer_dot_product
956 
957 INSTANTIATE_TEST_SUITE_P(
958     SPV_KHR_integer_dot_product, ExtensionRoundTripTest,
959     Combine(
960         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0,
961                SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
962         ValuesIn(std::vector<AssemblyCase>{
963             {"OpExtension \"SPV_KHR_integer_dot_product\"\n",
964              MakeInstruction(SpvOpExtension,
965                              MakeVector("SPV_KHR_integer_dot_product"))},
966             {"OpCapability DotProductInputAllKHR\n",
967              MakeInstruction(SpvOpCapability,
968                              {SpvCapabilityDotProductInputAllKHR})},
969             {"OpCapability DotProductInput4x8BitKHR\n",
970              MakeInstruction(SpvOpCapability,
971                              {SpvCapabilityDotProductInput4x8BitKHR})},
972             {"OpCapability DotProductInput4x8BitPackedKHR\n",
973              MakeInstruction(SpvOpCapability,
974                              {SpvCapabilityDotProductInput4x8BitPackedKHR})},
975             {"OpCapability DotProductKHR\n",
976              MakeInstruction(SpvOpCapability, {SpvCapabilityDotProductKHR})},
977             {"%2 = OpSDotKHR %1 %3 %4\n",
978              MakeInstruction(SpvOpSDotKHR, {1, 2, 3, 4})},
979             {"%2 = OpSDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
980              MakeInstruction(
981                  SpvOpSDotKHR,
982                  {1, 2, 3, 4,
983                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
984             {"%2 = OpUDotKHR %1 %3 %4\n",
985              MakeInstruction(SpvOpUDotKHR, {1, 2, 3, 4})},
986             {"%2 = OpUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
987              MakeInstruction(
988                  SpvOpUDotKHR,
989                  {1, 2, 3, 4,
990                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
991             {"%2 = OpSUDotKHR %1 %3 %4\n",
992              MakeInstruction(SpvOpSUDotKHR, {1, 2, 3, 4})},
993             {"%2 = OpSUDotKHR %1 %3 %4 PackedVectorFormat4x8BitKHR\n",
994              MakeInstruction(
995                  SpvOpSUDotKHR,
996                  {1, 2, 3, 4,
997                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
998             {"%2 = OpSDotAccSatKHR %1 %3 %4 %5\n",
999              MakeInstruction(SpvOpSDotAccSatKHR, {1, 2, 3, 4, 5})},
1000             {"%2 = OpSDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
1001              MakeInstruction(
1002                  SpvOpSDotAccSatKHR,
1003                  {1, 2, 3, 4, 5,
1004                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
1005             {"%2 = OpUDotAccSatKHR %1 %3 %4 %5\n",
1006              MakeInstruction(SpvOpUDotAccSatKHR, {1, 2, 3, 4, 5})},
1007             {"%2 = OpUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
1008              MakeInstruction(
1009                  SpvOpUDotAccSatKHR,
1010                  {1, 2, 3, 4, 5,
1011                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
1012             {"%2 = OpSUDotAccSatKHR %1 %3 %4 %5\n",
1013              MakeInstruction(SpvOpSUDotAccSatKHR, {1, 2, 3, 4, 5})},
1014             {"%2 = OpSUDotAccSatKHR %1 %3 %4 %5 PackedVectorFormat4x8BitKHR\n",
1015              MakeInstruction(
1016                  SpvOpSUDotAccSatKHR,
1017                  {1, 2, 3, 4, 5,
1018                   SpvPackedVectorFormatPackedVectorFormat4x8BitKHR})},
1019         })));
1020 
1021 // SPV_KHR_bit_instructions
1022 
1023 INSTANTIATE_TEST_SUITE_P(
1024     SPV_KHR_bit_instructions, ExtensionRoundTripTest,
1025     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5,
1026                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2),
1027             ValuesIn(std::vector<AssemblyCase>{
1028                 {"OpExtension \"SPV_KHR_bit_instructions\"\n",
1029                  MakeInstruction(SpvOpExtension,
1030                                  MakeVector("SPV_KHR_bit_instructions"))},
1031                 {"OpCapability BitInstructions\n",
1032                  MakeInstruction(SpvOpCapability,
1033                                  {SpvCapabilityBitInstructions})},
1034             })));
1035 
1036 }  // namespace
1037 }  // namespace spvtools
1038