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