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 "test/test_fixture.h"
26 #include "test/unit_spirv.h"
27 
28 namespace spvtools {
29 namespace {
30 
31 using spvtest::Concatenate;
32 using spvtest::MakeInstruction;
33 using spvtest::MakeVector;
34 using spvtest::TextToBinaryTest;
35 using ::testing::Combine;
36 using ::testing::Eq;
37 using ::testing::Values;
38 using ::testing::ValuesIn;
39 
40 // Returns a generator of common Vulkan environment values to be tested.
CommonVulkanEnvs()41 std::vector<spv_target_env> CommonVulkanEnvs() {
42   return {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
43           SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,    SPV_ENV_VULKAN_1_1};
44 }
45 
TEST_F(TextToBinaryTest,InvalidExtInstImportName)46 TEST_F(TextToBinaryTest, InvalidExtInstImportName) {
47   EXPECT_THAT(CompileFailure("%1 = OpExtInstImport \"Haskell.std\""),
48               Eq("Invalid extended instruction import 'Haskell.std'"));
49 }
50 
TEST_F(TextToBinaryTest,InvalidImportId)51 TEST_F(TextToBinaryTest, InvalidImportId) {
52   EXPECT_THAT(CompileFailure("%1 = OpTypeVoid\n"
53                              "%2 = OpExtInst %1 %1"),
54               Eq("Invalid extended instruction import Id 2"));
55 }
56 
TEST_F(TextToBinaryTest,InvalidImportInstruction)57 TEST_F(TextToBinaryTest, InvalidImportInstruction) {
58   const std::string input = R"(%1 = OpTypeVoid
59                                %2 = OpExtInstImport "OpenCL.std"
60                                %3 = OpExtInst %1 %2 not_in_the_opencl)";
61   EXPECT_THAT(CompileFailure(input),
62               Eq("Invalid extended instruction name 'not_in_the_opencl'."));
63 }
64 
TEST_F(TextToBinaryTest,MultiImport)65 TEST_F(TextToBinaryTest, MultiImport) {
66   const std::string input = R"(%2 = OpExtInstImport "OpenCL.std"
67                                %2 = OpExtInstImport "OpenCL.std")";
68   EXPECT_THAT(CompileFailure(input),
69               Eq("Import Id is being defined a second time"));
70 }
71 
TEST_F(TextToBinaryTest,TooManyArguments)72 TEST_F(TextToBinaryTest, TooManyArguments) {
73   const std::string input = R"(%opencl = OpExtInstImport "OpenCL.std"
74                                %2 = OpExtInst %float %opencl cos %x %oops")";
75   EXPECT_THAT(CompileFailure(input), Eq("Expected '=', found end of stream."));
76 }
77 
78 TEST_F(TextToBinaryTest, ExtInstFromTwoDifferentImports) {
79   const std::string input = R"(%1 = OpExtInstImport "OpenCL.std"
80 %2 = OpExtInstImport "GLSL.std.450"
81 %4 = OpExtInst %3 %1 native_sqrt %5
82 %7 = OpExtInst %6 %2 MatrixInverse %8
83 )";
84 
85   // Make sure it assembles correctly.
86   EXPECT_THAT(
87       CompiledInstructions(input),
88       Eq(Concatenate({
89           MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
90           MakeInstruction(SpvOpExtInstImport, {2}, MakeVector("GLSL.std.450")),
91           MakeInstruction(
92               SpvOpExtInst,
93               {3, 4, 1, uint32_t(OpenCLLIB::Entrypoints::Native_sqrt), 5}),
94           MakeInstruction(SpvOpExtInst,
95                           {6, 7, 2, uint32_t(GLSLstd450MatrixInverse), 8}),
96       })));
97 
98   // Make sure it disassembles correctly.
99   EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(input));
100 }
101 
102 // A test case for assembling into words in an instruction.
103 struct AssemblyCase {
104   std::string input;
105   std::vector<uint32_t> expected;
106 };
107 
108 using ExtensionAssemblyTest = spvtest::TextToBinaryTestBase<
109     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
110 
111 TEST_P(ExtensionAssemblyTest, Samples) {
112   const spv_target_env& env = std::get<0>(GetParam());
113   const AssemblyCase& ac = std::get<1>(GetParam());
114 
115   // Check that it assembles correctly.
116   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
117 }
118 
119 using ExtensionRoundTripTest = spvtest::TextToBinaryTestBase<
120     ::testing::TestWithParam<std::tuple<spv_target_env, AssemblyCase>>>;
121 
122 TEST_P(ExtensionRoundTripTest, Samples) {
123   const spv_target_env& env = std::get<0>(GetParam());
124   const AssemblyCase& ac = std::get<1>(GetParam());
125 
126   // Check that it assembles correctly.
127   EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected));
128 
129   // Check round trip through the disassembler.
130   EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input,
131                                           SPV_BINARY_TO_TEXT_OPTION_NONE, env),
132               Eq(ac.input))
133       << "target env: " << spvTargetEnvDescription(env) << "\n";
134 }
135 
136 // SPV_KHR_shader_ballot
137 
138 INSTANTIATE_TEST_CASE_P(
139     SPV_KHR_shader_ballot, ExtensionRoundTripTest,
140     // We'll get coverage over operand tables by trying the universal
141     // environments, and at least one specific environment.
142     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
143                    SPV_ENV_VULKAN_1_0),
144             ValuesIn(std::vector<AssemblyCase>{
145                 {"OpCapability SubgroupBallotKHR\n",
146                  MakeInstruction(SpvOpCapability,
147                                  {SpvCapabilitySubgroupBallotKHR})},
148                 {"%2 = OpSubgroupBallotKHR %1 %3\n",
149                  MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
150                 {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
151                  MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
152                 {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
153                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
154                                                  SpvBuiltInSubgroupEqMaskKHR})},
155                 {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
156                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
157                                                  SpvBuiltInSubgroupGeMaskKHR})},
158                 {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
159                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
160                                                  SpvBuiltInSubgroupGtMaskKHR})},
161                 {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
162                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
163                                                  SpvBuiltInSubgroupLeMaskKHR})},
164                 {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
165                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
166                                                  SpvBuiltInSubgroupLtMaskKHR})},
167             })), );
168 
169 INSTANTIATE_TEST_CASE_P(
170     SPV_KHR_shader_ballot_vulkan_1_1, ExtensionRoundTripTest,
171     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
172     // builtin enums.
173     Combine(Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
174             ValuesIn(std::vector<AssemblyCase>{
175                 {"OpCapability SubgroupBallotKHR\n",
176                  MakeInstruction(SpvOpCapability,
177                                  {SpvCapabilitySubgroupBallotKHR})},
178                 {"%2 = OpSubgroupBallotKHR %1 %3\n",
179                  MakeInstruction(SpvOpSubgroupBallotKHR, {1, 2, 3})},
180                 {"%2 = OpSubgroupFirstInvocationKHR %1 %3\n",
181                  MakeInstruction(SpvOpSubgroupFirstInvocationKHR, {1, 2, 3})},
182                 {"OpDecorate %1 BuiltIn SubgroupEqMask\n",
183                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
184                                                  SpvBuiltInSubgroupEqMask})},
185                 {"OpDecorate %1 BuiltIn SubgroupGeMask\n",
186                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
187                                                  SpvBuiltInSubgroupGeMask})},
188                 {"OpDecorate %1 BuiltIn SubgroupGtMask\n",
189                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
190                                                  SpvBuiltInSubgroupGtMask})},
191                 {"OpDecorate %1 BuiltIn SubgroupLeMask\n",
192                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
193                                                  SpvBuiltInSubgroupLeMask})},
194                 {"OpDecorate %1 BuiltIn SubgroupLtMask\n",
195                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
196                                                  SpvBuiltInSubgroupLtMask})},
197             })), );
198 
199 // The old builtin names (with KHR suffix) still work in the assmebler, and
200 // map to the enums without the KHR.
201 INSTANTIATE_TEST_CASE_P(
202     SPV_KHR_shader_ballot_vulkan_1_1_alias_check, ExtensionAssemblyTest,
203     // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the
204     // builtin enums.
205     Combine(Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
206             ValuesIn(std::vector<AssemblyCase>{
207                 {"OpDecorate %1 BuiltIn SubgroupEqMaskKHR\n",
208                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
209                                                  SpvBuiltInSubgroupEqMask})},
210                 {"OpDecorate %1 BuiltIn SubgroupGeMaskKHR\n",
211                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
212                                                  SpvBuiltInSubgroupGeMask})},
213                 {"OpDecorate %1 BuiltIn SubgroupGtMaskKHR\n",
214                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
215                                                  SpvBuiltInSubgroupGtMask})},
216                 {"OpDecorate %1 BuiltIn SubgroupLeMaskKHR\n",
217                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
218                                                  SpvBuiltInSubgroupLeMask})},
219                 {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n",
220                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
221                                                  SpvBuiltInSubgroupLtMask})},
222             })), );
223 
224 // SPV_KHR_shader_draw_parameters
225 
226 INSTANTIATE_TEST_CASE_P(
227     SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest,
228     // We'll get coverage over operand tables by trying the universal
229     // environments, and at least one specific environment.
230     Combine(
231         ValuesIn(CommonVulkanEnvs()),
232         ValuesIn(std::vector<AssemblyCase>{
233             {"OpCapability DrawParameters\n",
234              MakeInstruction(SpvOpCapability, {SpvCapabilityDrawParameters})},
235             {"OpDecorate %1 BuiltIn BaseVertex\n",
236              MakeInstruction(SpvOpDecorate,
237                              {1, SpvDecorationBuiltIn, SpvBuiltInBaseVertex})},
238             {"OpDecorate %1 BuiltIn BaseInstance\n",
239              MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
240                                              SpvBuiltInBaseInstance})},
241             {"OpDecorate %1 BuiltIn DrawIndex\n",
242              MakeInstruction(SpvOpDecorate,
243                              {1, SpvDecorationBuiltIn, SpvBuiltInDrawIndex})},
244         })), );
245 
246 // SPV_KHR_subgroup_vote
247 
248 INSTANTIATE_TEST_CASE_P(
249     SPV_KHR_subgroup_vote, ExtensionRoundTripTest,
250     // We'll get coverage over operand tables by trying the universal
251     // environments, and at least one specific environment.
252     Combine(ValuesIn(CommonVulkanEnvs()),
253             ValuesIn(std::vector<AssemblyCase>{
254                 {"OpCapability SubgroupVoteKHR\n",
255                  MakeInstruction(SpvOpCapability,
256                                  {SpvCapabilitySubgroupVoteKHR})},
257                 {"%2 = OpSubgroupAnyKHR %1 %3\n",
258                  MakeInstruction(SpvOpSubgroupAnyKHR, {1, 2, 3})},
259                 {"%2 = OpSubgroupAllKHR %1 %3\n",
260                  MakeInstruction(SpvOpSubgroupAllKHR, {1, 2, 3})},
261                 {"%2 = OpSubgroupAllEqualKHR %1 %3\n",
262                  MakeInstruction(SpvOpSubgroupAllEqualKHR, {1, 2, 3})},
263             })), );
264 
265 // SPV_KHR_16bit_storage
266 
267 INSTANTIATE_TEST_CASE_P(
268     SPV_KHR_16bit_storage, ExtensionRoundTripTest,
269     // We'll get coverage over operand tables by trying the universal
270     // environments, and at least one specific environment.
271     Combine(ValuesIn(CommonVulkanEnvs()),
272             ValuesIn(std::vector<AssemblyCase>{
273                 {"OpCapability StorageBuffer16BitAccess\n",
274                  MakeInstruction(SpvOpCapability,
275                                  {SpvCapabilityStorageUniformBufferBlock16})},
276                 {"OpCapability StorageBuffer16BitAccess\n",
277                  MakeInstruction(SpvOpCapability,
278                                  {SpvCapabilityStorageBuffer16BitAccess})},
279                 {"OpCapability StorageUniform16\n",
280                  MakeInstruction(
281                      SpvOpCapability,
282                      {SpvCapabilityUniformAndStorageBuffer16BitAccess})},
283                 {"OpCapability StorageUniform16\n",
284                  MakeInstruction(SpvOpCapability,
285                                  {SpvCapabilityStorageUniform16})},
286                 {"OpCapability StoragePushConstant16\n",
287                  MakeInstruction(SpvOpCapability,
288                                  {SpvCapabilityStoragePushConstant16})},
289                 {"OpCapability StorageInputOutput16\n",
290                  MakeInstruction(SpvOpCapability,
291                                  {SpvCapabilityStorageInputOutput16})},
292             })), );
293 
294 INSTANTIATE_TEST_CASE_P(
295     SPV_KHR_16bit_storage_alias_check, ExtensionAssemblyTest,
296     Combine(ValuesIn(CommonVulkanEnvs()),
297             ValuesIn(std::vector<AssemblyCase>{
298                 // The old name maps to the new enum.
299                 {"OpCapability StorageUniformBufferBlock16\n",
300                  MakeInstruction(SpvOpCapability,
301                                  {SpvCapabilityStorageBuffer16BitAccess})},
302                 // The new name maps to the old enum.
303                 {"OpCapability UniformAndStorageBuffer16BitAccess\n",
304                  MakeInstruction(SpvOpCapability,
305                                  {SpvCapabilityStorageUniform16})},
306             })), );
307 
308 // SPV_KHR_device_group
309 
310 INSTANTIATE_TEST_CASE_P(
311     SPV_KHR_device_group, ExtensionRoundTripTest,
312     // We'll get coverage over operand tables by trying the universal
313     // environments, and at least one specific environment.
314     Combine(ValuesIn(CommonVulkanEnvs()),
315             ValuesIn(std::vector<AssemblyCase>{
316                 {"OpCapability DeviceGroup\n",
317                  MakeInstruction(SpvOpCapability, {SpvCapabilityDeviceGroup})},
318                 {"OpDecorate %1 BuiltIn DeviceIndex\n",
319                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
320                                                  SpvBuiltInDeviceIndex})},
321             })), );
322 
323 // SPV_KHR_8bit_storage
324 
325 INSTANTIATE_TEST_CASE_P(
326     SPV_KHR_8bit_storage, ExtensionRoundTripTest,
327     // We'll get coverage over operand tables by trying the universal
328     // environments, and at least one specific environment.
329     Combine(
330         ValuesIn(CommonVulkanEnvs()),
331         ValuesIn(std::vector<AssemblyCase>{
332             {"OpCapability StorageBuffer8BitAccess\n",
333              MakeInstruction(SpvOpCapability,
334                              {SpvCapabilityStorageBuffer8BitAccess})},
335             {"OpCapability UniformAndStorageBuffer8BitAccess\n",
336              MakeInstruction(SpvOpCapability,
337                              {SpvCapabilityUniformAndStorageBuffer8BitAccess})},
338             {"OpCapability StoragePushConstant8\n",
339              MakeInstruction(SpvOpCapability,
340                              {SpvCapabilityStoragePushConstant8})},
341         })), );
342 
343 // SPV_KHR_multiview
344 
345 INSTANTIATE_TEST_CASE_P(
346     SPV_KHR_multiview, ExtensionRoundTripTest,
347     // We'll get coverage over operand tables by trying the universal
348     // environments, and at least one specific environment.
349     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
350                    SPV_ENV_VULKAN_1_0),
351             ValuesIn(std::vector<AssemblyCase>{
352                 {"OpCapability MultiView\n",
353                  MakeInstruction(SpvOpCapability, {SpvCapabilityMultiView})},
354                 {"OpDecorate %1 BuiltIn ViewIndex\n",
355                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
356                                                  SpvBuiltInViewIndex})},
357             })), );
358 
359 // SPV_AMD_shader_explicit_vertex_parameter
360 
361 #define PREAMBLE \
362   "%1 = OpExtInstImport \"SPV_AMD_shader_explicit_vertex_parameter\"\n"
363 INSTANTIATE_TEST_CASE_P(
364     SPV_AMD_shader_explicit_vertex_parameter, ExtensionRoundTripTest,
365     // We'll get coverage over operand tables by trying the universal
366     // environments, and at least one specific environment.
367     Combine(
368         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
369                SPV_ENV_VULKAN_1_0),
370         ValuesIn(std::vector<AssemblyCase>{
371             {PREAMBLE "%3 = OpExtInst %2 %1 InterpolateAtVertexAMD %4 %5\n",
372              Concatenate(
373                  {MakeInstruction(
374                       SpvOpExtInstImport, {1},
375                       MakeVector("SPV_AMD_shader_explicit_vertex_parameter")),
376                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5})})},
377         })), );
378 #undef PREAMBLE
379 
380 // SPV_AMD_shader_trinary_minmax
381 
382 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_trinary_minmax\"\n"
383 INSTANTIATE_TEST_CASE_P(
384     SPV_AMD_shader_trinary_minmax, ExtensionRoundTripTest,
385     // We'll get coverage over operand tables by trying the universal
386     // environments, and at least one specific environment.
387     Combine(
388         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
389                SPV_ENV_VULKAN_1_0),
390         ValuesIn(std::vector<AssemblyCase>{
391             {PREAMBLE "%3 = OpExtInst %2 %1 FMin3AMD %4 %5 %6\n",
392              Concatenate(
393                  {MakeInstruction(SpvOpExtInstImport, {1},
394                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
395                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5, 6})})},
396             {PREAMBLE "%3 = OpExtInst %2 %1 UMin3AMD %4 %5 %6\n",
397              Concatenate(
398                  {MakeInstruction(SpvOpExtInstImport, {1},
399                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
400                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4, 5, 6})})},
401             {PREAMBLE "%3 = OpExtInst %2 %1 SMin3AMD %4 %5 %6\n",
402              Concatenate(
403                  {MakeInstruction(SpvOpExtInstImport, {1},
404                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
405                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 3, 4, 5, 6})})},
406             {PREAMBLE "%3 = OpExtInst %2 %1 FMax3AMD %4 %5 %6\n",
407              Concatenate(
408                  {MakeInstruction(SpvOpExtInstImport, {1},
409                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
410                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 4, 4, 5, 6})})},
411             {PREAMBLE "%3 = OpExtInst %2 %1 UMax3AMD %4 %5 %6\n",
412              Concatenate(
413                  {MakeInstruction(SpvOpExtInstImport, {1},
414                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
415                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 5, 4, 5, 6})})},
416             {PREAMBLE "%3 = OpExtInst %2 %1 SMax3AMD %4 %5 %6\n",
417              Concatenate(
418                  {MakeInstruction(SpvOpExtInstImport, {1},
419                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
420                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 6, 4, 5, 6})})},
421             {PREAMBLE "%3 = OpExtInst %2 %1 FMid3AMD %4 %5 %6\n",
422              Concatenate(
423                  {MakeInstruction(SpvOpExtInstImport, {1},
424                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
425                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 7, 4, 5, 6})})},
426             {PREAMBLE "%3 = OpExtInst %2 %1 UMid3AMD %4 %5 %6\n",
427              Concatenate(
428                  {MakeInstruction(SpvOpExtInstImport, {1},
429                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
430                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 8, 4, 5, 6})})},
431             {PREAMBLE "%3 = OpExtInst %2 %1 SMid3AMD %4 %5 %6\n",
432              Concatenate(
433                  {MakeInstruction(SpvOpExtInstImport, {1},
434                                   MakeVector("SPV_AMD_shader_trinary_minmax")),
435                   MakeInstruction(SpvOpExtInst, {2, 3, 1, 9, 4, 5, 6})})},
436         })), );
437 #undef PREAMBLE
438 
439 // SPV_AMD_gcn_shader
440 
441 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n"
442 INSTANTIATE_TEST_CASE_P(
443     SPV_AMD_gcn_shader, ExtensionRoundTripTest,
444     // We'll get coverage over operand tables by trying the universal
445     // environments, and at least one specific environment.
446     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
447                    SPV_ENV_VULKAN_1_0),
448             ValuesIn(std::vector<AssemblyCase>{
449                 {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceIndexAMD %4\n",
450                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
451                                               MakeVector("SPV_AMD_gcn_shader")),
452                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4})})},
453                 {PREAMBLE "%3 = OpExtInst %2 %1 CubeFaceCoordAMD %4\n",
454                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
455                                               MakeVector("SPV_AMD_gcn_shader")),
456                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4})})},
457                 {PREAMBLE "%3 = OpExtInst %2 %1 TimeAMD\n",
458                  Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
459                                               MakeVector("SPV_AMD_gcn_shader")),
460                               MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})},
461             })), );
462 #undef PREAMBLE
463 
464 // SPV_AMD_shader_ballot
465 
466 #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_ballot\"\n"
467 INSTANTIATE_TEST_CASE_P(
468     SPV_AMD_shader_ballot, ExtensionRoundTripTest,
469     // We'll get coverage over operand tables by trying the universal
470     // environments, and at least one specific environment.
471     Combine(
472         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
473                SPV_ENV_VULKAN_1_0),
474         ValuesIn(std::vector<AssemblyCase>{
475             {PREAMBLE "%3 = OpExtInst %2 %1 SwizzleInvocationsAMD %4 %5\n",
476              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
477                                           MakeVector("SPV_AMD_shader_ballot")),
478                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5})})},
479             {PREAMBLE
480              "%3 = OpExtInst %2 %1 SwizzleInvocationsMaskedAMD %4 %5\n",
481              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
482                                           MakeVector("SPV_AMD_shader_ballot")),
483                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 2, 4, 5})})},
484             {PREAMBLE "%3 = OpExtInst %2 %1 WriteInvocationAMD %4 %5 %6\n",
485              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
486                                           MakeVector("SPV_AMD_shader_ballot")),
487                           MakeInstruction(SpvOpExtInst,
488                                           {2, 3, 1, 3, 4, 5, 6})})},
489             {PREAMBLE "%3 = OpExtInst %2 %1 MbcntAMD %4\n",
490              Concatenate({MakeInstruction(SpvOpExtInstImport, {1},
491                                           MakeVector("SPV_AMD_shader_ballot")),
492                           MakeInstruction(SpvOpExtInst, {2, 3, 1, 4, 4})})},
493         })), );
494 #undef PREAMBLE
495 
496 // SPV_KHR_variable_pointers
497 
498 INSTANTIATE_TEST_CASE_P(
499     SPV_KHR_variable_pointers, ExtensionRoundTripTest,
500     // We'll get coverage over operand tables by trying the universal
501     // environments, and at least one specific environment.
502     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
503                    SPV_ENV_VULKAN_1_0),
504             ValuesIn(std::vector<AssemblyCase>{
505                 {"OpCapability VariablePointers\n",
506                  MakeInstruction(SpvOpCapability,
507                                  {SpvCapabilityVariablePointers})},
508                 {"OpCapability VariablePointersStorageBuffer\n",
509                  MakeInstruction(SpvOpCapability,
510                                  {SpvCapabilityVariablePointersStorageBuffer})},
511             })), );
512 
513 // SPV_KHR_vulkan_memory_model
514 
515 INSTANTIATE_TEST_CASE_P(
516     SPV_KHR_vulkan_memory_model, ExtensionRoundTripTest,
517     // We'll get coverage over operand tables by trying the universal
518     // environments, and at least one specific environment.
519     //
520     // Note: SPV_KHR_vulkan_memory_model adds scope enum value QueueFamilyKHR.
521     // Scope enums are used in ID definitions elsewhere, that don't know they
522     // are using particular enums.  So the assembler doesn't support assembling
523     // those enums names into the corresponding values.  So there is no asm/dis
524     // tests for those enums.
525     Combine(
526         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
527                SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
528         ValuesIn(std::vector<AssemblyCase>{
529             {"OpCapability VulkanMemoryModelKHR\n",
530              MakeInstruction(SpvOpCapability,
531                              {SpvCapabilityVulkanMemoryModelKHR})},
532             {"OpCapability VulkanMemoryModelDeviceScopeKHR\n",
533              MakeInstruction(SpvOpCapability,
534                              {SpvCapabilityVulkanMemoryModelDeviceScopeKHR})},
535             {"OpMemoryModel Logical VulkanKHR\n",
536              MakeInstruction(SpvOpMemoryModel, {SpvAddressingModelLogical,
537                                                 SpvMemoryModelVulkanKHR})},
538             {"OpStore %1 %2 MakePointerAvailableKHR %3\n",
539              MakeInstruction(SpvOpStore,
540                              {1, 2, SpvMemoryAccessMakePointerAvailableKHRMask,
541                               3})},
542             {"OpStore %1 %2 Volatile|MakePointerAvailableKHR %3\n",
543              MakeInstruction(SpvOpStore,
544                              {1, 2,
545                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
546                                   int(SpvMemoryAccessVolatileMask),
547                               3})},
548             {"OpStore %1 %2 Aligned|MakePointerAvailableKHR 4 %3\n",
549              MakeInstruction(SpvOpStore,
550                              {1, 2,
551                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
552                                   int(SpvMemoryAccessAlignedMask),
553                               4, 3})},
554             {"OpStore %1 %2 MakePointerAvailableKHR|NonPrivatePointerKHR %3\n",
555              MakeInstruction(SpvOpStore,
556                              {1, 2,
557                               int(SpvMemoryAccessMakePointerAvailableKHRMask) |
558                                   int(SpvMemoryAccessNonPrivatePointerKHRMask),
559                               3})},
560             {"%2 = OpLoad %1 %3 MakePointerVisibleKHR %4\n",
561              MakeInstruction(SpvOpLoad,
562                              {1, 2, 3, SpvMemoryAccessMakePointerVisibleKHRMask,
563                               4})},
564             {"%2 = OpLoad %1 %3 Volatile|MakePointerVisibleKHR %4\n",
565              MakeInstruction(SpvOpLoad,
566                              {1, 2, 3,
567                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
568                                   int(SpvMemoryAccessVolatileMask),
569                               4})},
570             {"%2 = OpLoad %1 %3 Aligned|MakePointerVisibleKHR 8 %4\n",
571              MakeInstruction(SpvOpLoad,
572                              {1, 2, 3,
573                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
574                                   int(SpvMemoryAccessAlignedMask),
575                               8, 4})},
576             {"%2 = OpLoad %1 %3 MakePointerVisibleKHR|NonPrivatePointerKHR "
577              "%4\n",
578              MakeInstruction(SpvOpLoad,
579                              {1, 2, 3,
580                               int(SpvMemoryAccessMakePointerVisibleKHRMask) |
581                                   int(SpvMemoryAccessNonPrivatePointerKHRMask),
582                               4})},
583             {"OpCopyMemory %1 %2 "
584              "MakePointerAvailableKHR|"
585              "MakePointerVisibleKHR|"
586              "NonPrivatePointerKHR "
587              "%3 %4\n",
588              MakeInstruction(SpvOpCopyMemory,
589                              {1, 2,
590                               (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
591                                int(SpvMemoryAccessMakePointerAvailableKHRMask) |
592                                int(SpvMemoryAccessNonPrivatePointerKHRMask)),
593                               3, 4})},
594             {"OpCopyMemorySized %1 %2 %3 "
595              "MakePointerAvailableKHR|"
596              "MakePointerVisibleKHR|"
597              "NonPrivatePointerKHR "
598              "%4 %5\n",
599              MakeInstruction(SpvOpCopyMemorySized,
600                              {1, 2, 3,
601                               (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
602                                int(SpvMemoryAccessMakePointerAvailableKHRMask) |
603                                int(SpvMemoryAccessNonPrivatePointerKHRMask)),
604                               4, 5})},
605             // Image operands
606             {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR "
607              "%4\n",
608              MakeInstruction(
609                  SpvOpImageWrite,
610                  {1, 2, 3, int(SpvImageOperandsMakeTexelAvailableKHRMask), 4})},
611             {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR|NonPrivateTexelKHR "
612              "%4\n",
613              MakeInstruction(SpvOpImageWrite,
614                              {1, 2, 3,
615                               int(SpvImageOperandsMakeTexelAvailableKHRMask) |
616                                   int(SpvImageOperandsNonPrivateTexelKHRMask),
617                               4})},
618             {"OpImageWrite %1 %2 %3 "
619              "MakeTexelAvailableKHR|NonPrivateTexelKHR|VolatileTexelKHR "
620              "%4\n",
621              MakeInstruction(SpvOpImageWrite,
622                              {1, 2, 3,
623                               int(SpvImageOperandsMakeTexelAvailableKHRMask) |
624                                   int(SpvImageOperandsNonPrivateTexelKHRMask) |
625                                   int(SpvImageOperandsVolatileTexelKHRMask),
626                               4})},
627             {"%2 = OpImageRead %1 %3 %4 MakeTexelVisibleKHR "
628              "%5\n",
629              MakeInstruction(SpvOpImageRead,
630                              {1, 2, 3, 4,
631                               int(SpvImageOperandsMakeTexelVisibleKHRMask),
632                               5})},
633             {"%2 = OpImageRead %1 %3 %4 "
634              "MakeTexelVisibleKHR|NonPrivateTexelKHR "
635              "%5\n",
636              MakeInstruction(SpvOpImageRead,
637                              {1, 2, 3, 4,
638                               int(SpvImageOperandsMakeTexelVisibleKHRMask) |
639                                   int(SpvImageOperandsNonPrivateTexelKHRMask),
640                               5})},
641             {"%2 = OpImageRead %1 %3 %4 "
642              "MakeTexelVisibleKHR|NonPrivateTexelKHR|VolatileTexelKHR "
643              "%5\n",
644              MakeInstruction(SpvOpImageRead,
645                              {1, 2, 3, 4,
646                               int(SpvImageOperandsMakeTexelVisibleKHRMask) |
647                                   int(SpvImageOperandsNonPrivateTexelKHRMask) |
648                                   int(SpvImageOperandsVolatileTexelKHRMask),
649                               5})},
650 
651             // Memory semantics ID values are numbers put into a SPIR-V
652             // constant integer referenced by Id. There is no token for
653             // them, and so no assembler or disassembler support required.
654             // Similar for Scope ID.
655         })), );
656 
657 // SPV_GOOGLE_decorate_string
658 
659 INSTANTIATE_TEST_CASE_P(
660     SPV_GOOGLE_decorate_string, ExtensionRoundTripTest,
661     Combine(
662         // We'll get coverage over operand tables by trying the universal
663         // environments, and at least one specific environment.
664         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
665                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
666         ValuesIn(std::vector<AssemblyCase>{
667             {"OpDecorateStringGOOGLE %1 HlslSemanticGOOGLE \"ABC\"\n",
668              MakeInstruction(SpvOpDecorateStringGOOGLE,
669                              {1, SpvDecorationHlslSemanticGOOGLE},
670                              MakeVector("ABC"))},
671             {"OpMemberDecorateStringGOOGLE %1 3 HlslSemanticGOOGLE \"DEF\"\n",
672              MakeInstruction(SpvOpMemberDecorateStringGOOGLE,
673                              {1, 3, SpvDecorationHlslSemanticGOOGLE},
674                              MakeVector("DEF"))},
675         })), );
676 
677 // SPV_GOOGLE_hlsl_functionality1
678 
679 INSTANTIATE_TEST_CASE_P(
680     SPV_GOOGLE_hlsl_functionality1, ExtensionRoundTripTest,
681     Combine(
682         // We'll get coverage over operand tables by trying the universal
683         // environments, and at least one specific environment.
684         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
685                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0),
686         // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since
687         // they are coupled together.
688         ValuesIn(std::vector<AssemblyCase>{
689             {"OpDecorateId %1 HlslCounterBufferGOOGLE %2\n",
690              MakeInstruction(SpvOpDecorateId,
691                              {1, SpvDecorationHlslCounterBufferGOOGLE, 2})},
692         })), );
693 
694 // SPV_NV_viewport_array2
695 
696 INSTANTIATE_TEST_CASE_P(
697     SPV_NV_viewport_array2, ExtensionRoundTripTest,
698     Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
699                    SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3,
700                    SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
701             ValuesIn(std::vector<AssemblyCase>{
702                 {"OpExtension \"SPV_NV_viewport_array2\"\n",
703                  MakeInstruction(SpvOpExtension,
704                                  MakeVector("SPV_NV_viewport_array2"))},
705                 // The EXT and NV extensions have the same token number for this
706                 // capability.
707                 {"OpCapability ShaderViewportIndexLayerEXT\n",
708                  MakeInstruction(SpvOpCapability,
709                                  {SpvCapabilityShaderViewportIndexLayerNV})},
710                 // Check the new capability's token number
711                 {"OpCapability ShaderViewportIndexLayerEXT\n",
712                  MakeInstruction(SpvOpCapability, {5254})},
713                 // Decorations
714                 {"OpDecorate %1 ViewportRelativeNV\n",
715                  MakeInstruction(SpvOpDecorate,
716                                  {1, SpvDecorationViewportRelativeNV})},
717                 {"OpDecorate %1 BuiltIn ViewportMaskNV\n",
718                  MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn,
719                                                  SpvBuiltInViewportMaskNV})},
720             })), );
721 
722 // SPV_NV_shader_subgroup_partitioned
723 
724 INSTANTIATE_TEST_CASE_P(
725     SPV_NV_shader_subgroup_partitioned, ExtensionRoundTripTest,
726     Combine(
727         Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1),
728         ValuesIn(std::vector<AssemblyCase>{
729             {"OpExtension \"SPV_NV_shader_subgroup_partitioned\"\n",
730              MakeInstruction(SpvOpExtension,
731                              MakeVector("SPV_NV_shader_subgroup_partitioned"))},
732             {"OpCapability GroupNonUniformPartitionedNV\n",
733              MakeInstruction(SpvOpCapability,
734                              {SpvCapabilityGroupNonUniformPartitionedNV})},
735             // Check the new capability's token number
736             {"OpCapability GroupNonUniformPartitionedNV\n",
737              MakeInstruction(SpvOpCapability, {5297})},
738             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
739              MakeInstruction(SpvOpGroupNonUniformPartitionNV, {1, 2, 3})},
740             // Check the new instruction's token number
741             {"%2 = OpGroupNonUniformPartitionNV %1 %3\n",
742              MakeInstruction(static_cast<SpvOp>(5296), {1, 2, 3})},
743             // Check the new group operations
744             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
745              MakeInstruction(SpvOpGroupIAdd,
746                              {1, 2, 3, SpvGroupOperationPartitionedReduceNV,
747                               4})},
748             {"%2 = OpGroupIAdd %1 %3 PartitionedReduceNV %4\n",
749              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 6, 4})},
750             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
751              MakeInstruction(SpvOpGroupIAdd,
752                              {1, 2, 3,
753                               SpvGroupOperationPartitionedInclusiveScanNV, 4})},
754             {"%2 = OpGroupIAdd %1 %3 PartitionedInclusiveScanNV %4\n",
755              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 7, 4})},
756             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
757              MakeInstruction(SpvOpGroupIAdd,
758                              {1, 2, 3,
759                               SpvGroupOperationPartitionedExclusiveScanNV, 4})},
760             {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n",
761              MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 8, 4})},
762         })), );
763 
764 // SPV_EXT_descriptor_indexing
765 
766 INSTANTIATE_TEST_CASE_P(
767     SPV_EXT_descriptor_indexing, ExtensionRoundTripTest,
768     Combine(
769         Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
770                SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0,
771                SPV_ENV_VULKAN_1_1),
772         ValuesIn(std::vector<AssemblyCase>{
773             {"OpExtension \"SPV_EXT_descriptor_indexing\"\n",
774              MakeInstruction(SpvOpExtension,
775                              MakeVector("SPV_EXT_descriptor_indexing"))},
776             // Check capabilities, by name
777             {"OpCapability ShaderNonUniformEXT\n",
778              MakeInstruction(SpvOpCapability,
779                              {SpvCapabilityShaderNonUniformEXT})},
780             {"OpCapability RuntimeDescriptorArrayEXT\n",
781              MakeInstruction(SpvOpCapability,
782                              {SpvCapabilityRuntimeDescriptorArrayEXT})},
783             {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n",
784              MakeInstruction(
785                  SpvOpCapability,
786                  {SpvCapabilityInputAttachmentArrayDynamicIndexingEXT})},
787             {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n",
788              MakeInstruction(
789                  SpvOpCapability,
790                  {SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT})},
791             {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n",
792              MakeInstruction(
793                  SpvOpCapability,
794                  {SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT})},
795             {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n",
796              MakeInstruction(
797                  SpvOpCapability,
798                  {SpvCapabilityUniformBufferArrayNonUniformIndexingEXT})},
799             {"OpCapability SampledImageArrayNonUniformIndexingEXT\n",
800              MakeInstruction(
801                  SpvOpCapability,
802                  {SpvCapabilitySampledImageArrayNonUniformIndexingEXT})},
803             {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n",
804              MakeInstruction(
805                  SpvOpCapability,
806                  {SpvCapabilityStorageBufferArrayNonUniformIndexingEXT})},
807             {"OpCapability StorageImageArrayNonUniformIndexingEXT\n",
808              MakeInstruction(
809                  SpvOpCapability,
810                  {SpvCapabilityStorageImageArrayNonUniformIndexingEXT})},
811             {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n",
812              MakeInstruction(
813                  SpvOpCapability,
814                  {SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT})},
815             {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n",
816              MakeInstruction(
817                  SpvOpCapability,
818                  {SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT})},
819             {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n",
820              MakeInstruction(
821                  SpvOpCapability,
822                  {SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT})},
823             // Check capabilities, by number
824             {"OpCapability ShaderNonUniformEXT\n",
825              MakeInstruction(SpvOpCapability, {5301})},
826             {"OpCapability RuntimeDescriptorArrayEXT\n",
827              MakeInstruction(SpvOpCapability, {5302})},
828             {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n",
829              MakeInstruction(SpvOpCapability, {5303})},
830             {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n",
831              MakeInstruction(SpvOpCapability, {5304})},
832             {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n",
833              MakeInstruction(SpvOpCapability, {5305})},
834             {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n",
835              MakeInstruction(SpvOpCapability, {5306})},
836             {"OpCapability SampledImageArrayNonUniformIndexingEXT\n",
837              MakeInstruction(SpvOpCapability, {5307})},
838             {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n",
839              MakeInstruction(SpvOpCapability, {5308})},
840             {"OpCapability StorageImageArrayNonUniformIndexingEXT\n",
841              MakeInstruction(SpvOpCapability, {5309})},
842             {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n",
843              MakeInstruction(SpvOpCapability, {5310})},
844             {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n",
845              MakeInstruction(SpvOpCapability, {5311})},
846             {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n",
847              MakeInstruction(SpvOpCapability, {5312})},
848 
849             // Check the decoration token
850             {"OpDecorate %1 NonUniformEXT\n",
851              MakeInstruction(SpvOpDecorate, {1, SpvDecorationNonUniformEXT})},
852             {"OpDecorate %1 NonUniformEXT\n",
853              MakeInstruction(SpvOpDecorate, {1, 5300})},
854         })), );
855 
856 }  // namespace
857 }  // namespace spvtools
858