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
29namespace spvtools {
30namespace {
31
32using spvtest::Concatenate;
33using spvtest::MakeInstruction;
34using utils::MakeVector;
35using spvtest::TextToBinaryTest;
36using ::testing::Combine;
37using ::testing::Eq;
38using ::testing::Values;
39using ::testing::ValuesIn;
40
41// Returns a generator of common Vulkan environment values to be tested.
42std::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
47TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
48  EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
49              Eq("Invalid extended instruction import 'Haskell.std'"));
50}
51
52TEST_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
58TEST_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
66TEST_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
73TEST_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
79TEST_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.
106struct AssemblyCase {
107  std::string input;
108  std::vector<uint32_t> expected;
109};
110
111using ExtensionAssemblyTest = spvtest::TextToBinaryTestBase<
112    ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
113
114TEST_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
122using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
123    ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
124
125TEST_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
141INSTANTIATE_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
178INSTANTIATE_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.
216INSTANTIATE_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
246INSTANTIATE_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
271INSTANTIATE_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
290INSTANTIATE_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
323INSTANTIATE_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
341INSTANTIATE_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
358INSTANTIATE_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
381INSTANTIATE_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"
401INSTANTIATE_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"
421INSTANTIATE_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"
480INSTANTIATE_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"
508INSTANTIATE_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
542INSTANTIATE_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
561INSTANTIATE_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
728INSTANTIATE_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
754INSTANTIATE_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.
778INSTANTIATE_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
797INSTANTIATE_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
815INSTANTIATE_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
846INSTANTIATE_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
894INSTANTIATE_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
990INSTANTIATE_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
1009INSTANTIATE_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
1021INSTANTIATE_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
1038INSTANTIATE_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
1115INSTANTIATE_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
1130INSTANTIATE_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
1180INSTANTIATE_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
1203INSTANTIATE_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}  // namespace
1251}  // namespace spvtools
1252