1 // Copyright (c) 2016 Google 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 // Validation tests for Data Rules.
16
17 #include <sstream>
18 #include <string>
19 #include <utility>
20
21 #include "gmock/gmock.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24
25 namespace spvtools {
26 namespace val {
27 namespace {
28
29 using ::testing::HasSubstr;
30 using ::testing::MatchesRegex;
31
32 using ValidateData = spvtest::ValidateBase<std::pair<std::string, bool>>;
33
HeaderWith(std::string cap)34 std::string HeaderWith(std::string cap) {
35 return std::string("OpCapability Shader OpCapability Linkage OpCapability ") +
36 cap + " OpMemoryModel Logical GLSL450 ";
37 }
38
WebGPUHeaderWith(std::string cap)39 std::string WebGPUHeaderWith(std::string cap) {
40 return R"(
41 OpCapability Shader
42 OpCapability )" +
43 cap + R"(
44 OpCapability VulkanMemoryModelKHR
45 OpExtension "SPV_KHR_vulkan_memory_model"
46 OpMemoryModel Logical VulkanKHR
47 )";
48 }
49
50 std::string webgpu_header = R"(
51 OpCapability Shader
52 OpCapability VulkanMemoryModelKHR
53 OpExtension "SPV_KHR_vulkan_memory_model"
54 OpMemoryModel Logical VulkanKHR
55 )";
56
57 std::string header = R"(
58 OpCapability Shader
59 OpCapability Linkage
60 OpMemoryModel Logical GLSL450
61 )";
62 std::string header_with_addresses = R"(
63 OpCapability Addresses
64 OpCapability Kernel
65 OpCapability GenericPointer
66 OpCapability Linkage
67 OpMemoryModel Physical32 OpenCL
68 )";
69 std::string header_with_vec16_cap = R"(
70 OpCapability Shader
71 OpCapability Vector16
72 OpCapability Linkage
73 OpMemoryModel Logical GLSL450
74 )";
75 std::string header_with_int8 = R"(
76 OpCapability Shader
77 OpCapability Linkage
78 OpCapability Int8
79 OpMemoryModel Logical GLSL450
80 )";
81 std::string header_with_int16 = R"(
82 OpCapability Shader
83 OpCapability Linkage
84 OpCapability Int16
85 OpMemoryModel Logical GLSL450
86 )";
87 std::string header_with_int64 = R"(
88 OpCapability Shader
89 OpCapability Linkage
90 OpCapability Int64
91 OpMemoryModel Logical GLSL450
92 )";
93 std::string header_with_float16 = R"(
94 OpCapability Shader
95 OpCapability Linkage
96 OpCapability Float16
97 OpMemoryModel Logical GLSL450
98 )";
99 std::string header_with_float16_buffer = R"(
100 OpCapability Shader
101 OpCapability Linkage
102 OpCapability Float16Buffer
103 OpMemoryModel Logical GLSL450
104 )";
105 std::string header_with_float64 = R"(
106 OpCapability Shader
107 OpCapability Linkage
108 OpCapability Float64
109 OpMemoryModel Logical GLSL450
110 )";
111
112 std::string invalid_comp_error = "Illegal number of components";
113 std::string missing_cap_error = "requires the Vector16 capability";
114 std::string missing_int8_cap_error = "requires the Int8 capability";
115 std::string missing_int16_cap_error =
116 "requires the Int16 capability,"
117 " or an extension that explicitly enables 16-bit integers.";
118 std::string missing_int64_cap_error = "requires the Int64 capability";
119 std::string missing_float16_cap_error =
120 "requires the Float16 or Float16Buffer capability,"
121 " or an extension that explicitly enables 16-bit floating point.";
122 std::string missing_float64_cap_error = "requires the Float64 capability";
123 std::string invalid_num_bits_error = "Invalid number of bits";
124
TEST_F(ValidateData,vec0)125 TEST_F(ValidateData, vec0) {
126 std::string str = header + R"(
127 %1 = OpTypeFloat 32
128 %2 = OpTypeVector %1 0
129 )";
130 CompileSuccessfully(str.c_str());
131 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
132 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
133 }
134
TEST_F(ValidateData,vec1)135 TEST_F(ValidateData, vec1) {
136 std::string str = header + R"(
137 %1 = OpTypeFloat 32
138 %2 = OpTypeVector %1 1
139 )";
140 CompileSuccessfully(str.c_str());
141 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
142 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
143 }
144
TEST_F(ValidateData,vec2)145 TEST_F(ValidateData, vec2) {
146 std::string str = header + R"(
147 %1 = OpTypeFloat 32
148 %2 = OpTypeVector %1 2
149 )";
150 CompileSuccessfully(str.c_str());
151 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
152 }
153
TEST_F(ValidateData,vec3)154 TEST_F(ValidateData, vec3) {
155 std::string str = header + R"(
156 %1 = OpTypeFloat 32
157 %2 = OpTypeVector %1 3
158 )";
159 CompileSuccessfully(str.c_str());
160 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
161 }
162
TEST_F(ValidateData,vec4)163 TEST_F(ValidateData, vec4) {
164 std::string str = header + R"(
165 %1 = OpTypeFloat 32
166 %2 = OpTypeVector %1 4
167 )";
168 CompileSuccessfully(str.c_str());
169 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
170 }
171
TEST_F(ValidateData,vec5)172 TEST_F(ValidateData, vec5) {
173 std::string str = header + R"(
174 %1 = OpTypeFloat 32
175 %2 = OpTypeVector %1 5
176 )";
177 CompileSuccessfully(str.c_str());
178 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
179 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
180 }
181
TEST_F(ValidateData,vec8)182 TEST_F(ValidateData, vec8) {
183 std::string str = header + R"(
184 %1 = OpTypeFloat 32
185 %2 = OpTypeVector %1 8
186 )";
187 CompileSuccessfully(str.c_str());
188 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
189 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
190 }
191
TEST_F(ValidateData,vec8_with_capability)192 TEST_F(ValidateData, vec8_with_capability) {
193 std::string str = header_with_vec16_cap + R"(
194 %1 = OpTypeFloat 32
195 %2 = OpTypeVector %1 8
196 )";
197 CompileSuccessfully(str.c_str());
198 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
199 }
200
TEST_F(ValidateData,vec16)201 TEST_F(ValidateData, vec16) {
202 std::string str = header + R"(
203 %1 = OpTypeFloat 32
204 %2 = OpTypeVector %1 8
205 )";
206 CompileSuccessfully(str.c_str());
207 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
208 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
209 }
210
TEST_F(ValidateData,vec16_with_capability)211 TEST_F(ValidateData, vec16_with_capability) {
212 std::string str = header_with_vec16_cap + R"(
213 %1 = OpTypeFloat 32
214 %2 = OpTypeVector %1 16
215 )";
216 CompileSuccessfully(str.c_str());
217 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
218 }
219
TEST_F(ValidateData,vec15)220 TEST_F(ValidateData, vec15) {
221 std::string str = header + R"(
222 %1 = OpTypeFloat 32
223 %2 = OpTypeVector %1 15
224 )";
225 CompileSuccessfully(str.c_str());
226 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
227 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
228 }
229
TEST_F(ValidateData,int8_good)230 TEST_F(ValidateData, int8_good) {
231 std::string str = header_with_int8 + "%2 = OpTypeInt 8 0";
232 CompileSuccessfully(str.c_str());
233 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
234 }
235
TEST_F(ValidateData,int8_bad)236 TEST_F(ValidateData, int8_bad) {
237 std::string str = header + "%2 = OpTypeInt 8 1";
238 CompileSuccessfully(str.c_str());
239 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
240 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int8_cap_error));
241 }
242
TEST_F(ValidateData,int8_with_storage_buffer_8bit_access_good)243 TEST_F(ValidateData, int8_with_storage_buffer_8bit_access_good) {
244 std::string str = HeaderWith(
245 "StorageBuffer8BitAccess "
246 "OpExtension \"SPV_KHR_8bit_storage\"") +
247 " %2 = OpTypeInt 8 0";
248 CompileSuccessfully(str.c_str());
249 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
250 }
251
TEST_F(ValidateData,int8_with_uniform_and_storage_buffer_8bit_access_good)252 TEST_F(ValidateData, int8_with_uniform_and_storage_buffer_8bit_access_good) {
253 std::string str = HeaderWith(
254 "UniformAndStorageBuffer8BitAccess "
255 "OpExtension \"SPV_KHR_8bit_storage\"") +
256 " %2 = OpTypeInt 8 0";
257 CompileSuccessfully(str.c_str());
258 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
259 }
260
TEST_F(ValidateData,int8_with_storage_push_constant_8_good)261 TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
262 std::string str = HeaderWith(
263 "StoragePushConstant8 "
264 "OpExtension \"SPV_KHR_8bit_storage\"") +
265 " %2 = OpTypeInt 8 0";
266 CompileSuccessfully(str.c_str());
267 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
268 }
269
TEST_F(ValidateData,webgpu_int8_bad)270 TEST_F(ValidateData, webgpu_int8_bad) {
271 std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0";
272 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
273 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
274 ValidateInstructions(SPV_ENV_WEBGPU_0));
275 EXPECT_THAT(
276 getDiagnosticString(),
277 HasSubstr("Capability Int8 is not allowed by WebGPU specification (or "
278 "requires extension)\n"
279 " OpCapability Int8\n"));
280 }
281
TEST_F(ValidateData,int16_good)282 TEST_F(ValidateData, int16_good) {
283 std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
284 CompileSuccessfully(str.c_str());
285 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
286 }
287
TEST_F(ValidateData,storage_uniform_buffer_block_16_good)288 TEST_F(ValidateData, storage_uniform_buffer_block_16_good) {
289 std::string str = HeaderWith(
290 "StorageUniformBufferBlock16 "
291 "OpExtension \"SPV_KHR_16bit_storage\"") +
292 "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
293 CompileSuccessfully(str.c_str());
294 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
295 }
296
TEST_F(ValidateData,storage_uniform_16_good)297 TEST_F(ValidateData, storage_uniform_16_good) {
298 std::string str =
299 HeaderWith("StorageUniform16 OpExtension \"SPV_KHR_16bit_storage\"") +
300 "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
301 CompileSuccessfully(str.c_str());
302 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
303 }
304
TEST_F(ValidateData,storage_push_constant_16_good)305 TEST_F(ValidateData, storage_push_constant_16_good) {
306 std::string str = HeaderWith(
307 "StoragePushConstant16 "
308 "OpExtension \"SPV_KHR_16bit_storage\"") +
309 "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
310 CompileSuccessfully(str.c_str());
311 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
312 }
313
TEST_F(ValidateData,storage_input_output_16_good)314 TEST_F(ValidateData, storage_input_output_16_good) {
315 std::string str = HeaderWith(
316 "StorageInputOutput16 "
317 "OpExtension \"SPV_KHR_16bit_storage\"") +
318 "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
319 CompileSuccessfully(str.c_str());
320 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
321 }
322
TEST_F(ValidateData,amd_gpu_shader_half_float_fetch_16_good)323 TEST_F(ValidateData, amd_gpu_shader_half_float_fetch_16_good) {
324 std::string str = R"(
325 OpCapability Shader
326 OpCapability Linkage
327 OpExtension "SPV_AMD_gpu_shader_half_float_fetch"
328 OpMemoryModel Logical GLSL450
329 %2 = OpTypeFloat 16)";
330 CompileSuccessfully(str.c_str());
331 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
332 }
333
TEST_F(ValidateData,int16_bad)334 TEST_F(ValidateData, int16_bad) {
335 std::string str = header + "%2 = OpTypeInt 16 1";
336 CompileSuccessfully(str.c_str());
337 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
338 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
339 }
340
TEST_F(ValidateData,webgpu_int16_bad)341 TEST_F(ValidateData, webgpu_int16_bad) {
342 std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1";
343 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
344 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
345 ValidateInstructions(SPV_ENV_WEBGPU_0));
346 EXPECT_THAT(
347 getDiagnosticString(),
348 HasSubstr("Capability Int16 is not allowed by WebGPU specification (or "
349 "requires extension)\n"
350 " OpCapability Int16\n"));
351 }
352
TEST_F(ValidateData,webgpu_int32_good)353 TEST_F(ValidateData, webgpu_int32_good) {
354 std::string str = webgpu_header + R"(
355 OpEntryPoint Fragment %func "func"
356 OpExecutionMode %func OriginUpperLeft
357 %uint_t = OpTypeInt 32 0
358 %void = OpTypeVoid
359 %func_t = OpTypeFunction %void
360 %func = OpFunction %void None %func_t
361 %1 = OpLabel
362 OpReturn
363 OpFunctionEnd
364 )";
365 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
366 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
367 }
368
TEST_F(ValidateData,int64_good)369 TEST_F(ValidateData, int64_good) {
370 std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
371 CompileSuccessfully(str.c_str());
372 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
373 }
374
TEST_F(ValidateData,int64_bad)375 TEST_F(ValidateData, int64_bad) {
376 std::string str = header + "%2 = OpTypeInt 64 1";
377 CompileSuccessfully(str.c_str());
378 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
379 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
380 }
381
TEST_F(ValidateData,webgpu_int64_bad)382 TEST_F(ValidateData, webgpu_int64_bad) {
383 std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1";
384 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
385 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
386 ValidateInstructions(SPV_ENV_WEBGPU_0));
387 EXPECT_THAT(
388 getDiagnosticString(),
389 HasSubstr("Capability Int64 is not allowed by WebGPU specification (or "
390 "requires extension)\n"
391 " OpCapability Int64\n"));
392 }
393
394 // Number of bits in an integer may be only one of: {8,16,32,64}
TEST_F(ValidateData,int_invalid_num_bits)395 TEST_F(ValidateData, int_invalid_num_bits) {
396 std::string str = header + "%2 = OpTypeInt 48 1";
397 CompileSuccessfully(str.c_str());
398 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
399 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
400 }
401
TEST_F(ValidateData,float16_good)402 TEST_F(ValidateData, float16_good) {
403 std::string str = header_with_float16 + "%2 = OpTypeFloat 16";
404 CompileSuccessfully(str.c_str());
405 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
406 }
407
TEST_F(ValidateData,float16_buffer_good)408 TEST_F(ValidateData, float16_buffer_good) {
409 std::string str = header_with_float16_buffer + "%2 = OpTypeFloat 16";
410 CompileSuccessfully(str.c_str());
411 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
412 }
413
TEST_F(ValidateData,float16_bad)414 TEST_F(ValidateData, float16_bad) {
415 std::string str = header + "%2 = OpTypeFloat 16";
416 CompileSuccessfully(str.c_str());
417 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
418 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
419 }
420
TEST_F(ValidateData,webgpu_float16_bad)421 TEST_F(ValidateData, webgpu_float16_bad) {
422 std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16";
423 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
424 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
425 ValidateInstructions(SPV_ENV_WEBGPU_0));
426 EXPECT_THAT(
427 getDiagnosticString(),
428 HasSubstr("Capability Float16 is not allowed by WebGPU specification (or "
429 "requires extension)\n"
430 " OpCapability Float16\n"));
431 }
432
TEST_F(ValidateData,webgpu_float32_good)433 TEST_F(ValidateData, webgpu_float32_good) {
434 std::string str = webgpu_header + R"(
435 OpEntryPoint Fragment %func "func"
436 OpExecutionMode %func OriginUpperLeft
437 %float_t = OpTypeFloat 32
438 %void = OpTypeVoid
439 %func_t = OpTypeFunction %void
440 %func = OpFunction %void None %func_t
441 %1 = OpLabel
442 OpReturn
443 OpFunctionEnd
444 )";
445 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
446 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
447 }
448
TEST_F(ValidateData,float64_good)449 TEST_F(ValidateData, float64_good) {
450 std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
451 CompileSuccessfully(str.c_str());
452 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
453 }
454
TEST_F(ValidateData,float64_bad)455 TEST_F(ValidateData, float64_bad) {
456 std::string str = header + "%2 = OpTypeFloat 64";
457 CompileSuccessfully(str.c_str());
458 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
459 EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
460 }
461
TEST_F(ValidateData,webgpu_float64_bad)462 TEST_F(ValidateData, webgpu_float64_bad) {
463 std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64";
464 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
465 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
466 ValidateInstructions(SPV_ENV_WEBGPU_0));
467 EXPECT_THAT(
468 getDiagnosticString(),
469 HasSubstr("Capability Float64 is not allowed by WebGPU specification (or "
470 "requires extension)\n"
471 " OpCapability Float64\n"));
472 }
473
474 // Number of bits in a float may be only one of: {16,32,64}
TEST_F(ValidateData,float_invalid_num_bits)475 TEST_F(ValidateData, float_invalid_num_bits) {
476 std::string str = header + "%2 = OpTypeFloat 48";
477 CompileSuccessfully(str.c_str());
478 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
479 EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
480 }
481
TEST_F(ValidateData,matrix_data_type_float)482 TEST_F(ValidateData, matrix_data_type_float) {
483 std::string str = header + R"(
484 %f32 = OpTypeFloat 32
485 %vec3 = OpTypeVector %f32 3
486 %mat33 = OpTypeMatrix %vec3 3
487 )";
488 CompileSuccessfully(str.c_str());
489 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
490 }
491
TEST_F(ValidateData,ids_should_be_validated_before_data)492 TEST_F(ValidateData, ids_should_be_validated_before_data) {
493 std::string str = header + R"(
494 %f32 = OpTypeFloat 32
495 %mat33 = OpTypeMatrix %vec3 3
496 )";
497 CompileSuccessfully(str.c_str());
498 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
499 EXPECT_THAT(getDiagnosticString(),
500 HasSubstr("ID 3[%3] has not been defined"));
501 }
502
TEST_F(ValidateData,matrix_bad_column_type)503 TEST_F(ValidateData, matrix_bad_column_type) {
504 std::string str = header + R"(
505 %f32 = OpTypeFloat 32
506 %mat33 = OpTypeMatrix %f32 3
507 )";
508 CompileSuccessfully(str.c_str());
509 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
510 EXPECT_THAT(getDiagnosticString(),
511 HasSubstr("Columns in a matrix must be of type vector"));
512 }
513
TEST_F(ValidateData,matrix_data_type_int)514 TEST_F(ValidateData, matrix_data_type_int) {
515 std::string str = header + R"(
516 %int32 = OpTypeInt 32 1
517 %vec3 = OpTypeVector %int32 3
518 %mat33 = OpTypeMatrix %vec3 3
519 )";
520 CompileSuccessfully(str.c_str());
521 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
522 EXPECT_THAT(getDiagnosticString(),
523 HasSubstr("can only be parameterized with floating-point types"));
524 }
525
TEST_F(ValidateData,matrix_data_type_bool)526 TEST_F(ValidateData, matrix_data_type_bool) {
527 std::string str = header + R"(
528 %boolt = OpTypeBool
529 %vec3 = OpTypeVector %boolt 3
530 %mat33 = OpTypeMatrix %vec3 3
531 )";
532 CompileSuccessfully(str.c_str());
533 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
534 EXPECT_THAT(getDiagnosticString(),
535 HasSubstr("can only be parameterized with floating-point types"));
536 }
537
TEST_F(ValidateData,matrix_with_0_columns)538 TEST_F(ValidateData, matrix_with_0_columns) {
539 std::string str = header + R"(
540 %f32 = OpTypeFloat 32
541 %vec3 = OpTypeVector %f32 3
542 %mat33 = OpTypeMatrix %vec3 0
543 )";
544 CompileSuccessfully(str.c_str());
545 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
546 EXPECT_THAT(
547 getDiagnosticString(),
548 HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
549 }
550
TEST_F(ValidateData,matrix_with_1_column)551 TEST_F(ValidateData, matrix_with_1_column) {
552 std::string str = header + R"(
553 %f32 = OpTypeFloat 32
554 %vec3 = OpTypeVector %f32 3
555 %mat33 = OpTypeMatrix %vec3 1
556 )";
557 CompileSuccessfully(str.c_str());
558 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
559 EXPECT_THAT(
560 getDiagnosticString(),
561 HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
562 }
563
TEST_F(ValidateData,matrix_with_2_columns)564 TEST_F(ValidateData, matrix_with_2_columns) {
565 std::string str = header + R"(
566 %f32 = OpTypeFloat 32
567 %vec3 = OpTypeVector %f32 3
568 %mat33 = OpTypeMatrix %vec3 2
569 )";
570 CompileSuccessfully(str.c_str());
571 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
572 }
573
TEST_F(ValidateData,matrix_with_3_columns)574 TEST_F(ValidateData, matrix_with_3_columns) {
575 std::string str = header + R"(
576 %f32 = OpTypeFloat 32
577 %vec3 = OpTypeVector %f32 3
578 %mat33 = OpTypeMatrix %vec3 3
579 )";
580 CompileSuccessfully(str.c_str());
581 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
582 }
583
TEST_F(ValidateData,matrix_with_4_columns)584 TEST_F(ValidateData, matrix_with_4_columns) {
585 std::string str = header + R"(
586 %f32 = OpTypeFloat 32
587 %vec3 = OpTypeVector %f32 3
588 %mat33 = OpTypeMatrix %vec3 4
589 )";
590 CompileSuccessfully(str.c_str());
591 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
592 }
593
TEST_F(ValidateData,matrix_with_5_column)594 TEST_F(ValidateData, matrix_with_5_column) {
595 std::string str = header + R"(
596 %f32 = OpTypeFloat 32
597 %vec3 = OpTypeVector %f32 3
598 %mat33 = OpTypeMatrix %vec3 5
599 )";
600 CompileSuccessfully(str.c_str());
601 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
602 EXPECT_THAT(
603 getDiagnosticString(),
604 HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
605 }
606
TEST_F(ValidateData,specialize_int)607 TEST_F(ValidateData, specialize_int) {
608 std::string str = header + R"(
609 %i32 = OpTypeInt 32 1
610 %len = OpSpecConstant %i32 2)";
611 CompileSuccessfully(str.c_str());
612 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
613 }
614
TEST_F(ValidateData,specialize_float)615 TEST_F(ValidateData, specialize_float) {
616 std::string str = header + R"(
617 %f32 = OpTypeFloat 32
618 %len = OpSpecConstant %f32 2)";
619 CompileSuccessfully(str.c_str());
620 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
621 }
622
TEST_F(ValidateData,specialize_boolean)623 TEST_F(ValidateData, specialize_boolean) {
624 std::string str = header + R"(
625 %2 = OpTypeBool
626 %3 = OpSpecConstantTrue %2
627 %4 = OpSpecConstantFalse %2)";
628 CompileSuccessfully(str.c_str());
629 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
630 }
631
TEST_F(ValidateData,specialize_boolean_true_to_int)632 TEST_F(ValidateData, specialize_boolean_true_to_int) {
633 std::string str = header + R"(
634 %2 = OpTypeInt 32 1
635 %3 = OpSpecConstantTrue %2)";
636 CompileSuccessfully(str.c_str());
637 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
638 EXPECT_THAT(getDiagnosticString(),
639 HasSubstr("OpSpecConstantTrue Result Type <id> '1[%int]' is not "
640 "a boolean type"));
641 }
642
TEST_F(ValidateData,specialize_boolean_false_to_int)643 TEST_F(ValidateData, specialize_boolean_false_to_int) {
644 std::string str = header + R"(
645 %2 = OpTypeInt 32 1
646 %4 = OpSpecConstantFalse %2)";
647 CompileSuccessfully(str.c_str());
648 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
649 EXPECT_THAT(getDiagnosticString(),
650 HasSubstr("OpSpecConstantFalse Result Type <id> '1[%int]' is not "
651 "a boolean type"));
652 }
653
TEST_F(ValidateData,missing_forward_pointer_decl)654 TEST_F(ValidateData, missing_forward_pointer_decl) {
655 std::string str = header_with_addresses + R"(
656 %uintt = OpTypeInt 32 0
657 %3 = OpTypeStruct %fwd_ptrt %uintt
658 )";
659 CompileSuccessfully(str.c_str());
660 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
661 EXPECT_THAT(getDiagnosticString(),
662 HasSubstr("Operand 3[%3] requires a previous definition"));
663 }
664
TEST_F(ValidateData,missing_forward_pointer_decl_self_reference)665 TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) {
666 std::string str = header_with_addresses + R"(
667 %uintt = OpTypeInt 32 0
668 %3 = OpTypeStruct %3 %uintt
669 )";
670 CompileSuccessfully(str.c_str());
671 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
672 EXPECT_THAT(
673 getDiagnosticString(),
674 HasSubstr("Operand 2[%_struct_2] requires a previous definition"));
675 }
676
TEST_F(ValidateData,forward_pointer_missing_definition)677 TEST_F(ValidateData, forward_pointer_missing_definition) {
678 std::string str = header_with_addresses + R"(
679 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
680 %uintt = OpTypeInt 32 0
681 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
682 )";
683 CompileSuccessfully(str.c_str());
684 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
685 EXPECT_THAT(getDiagnosticString(),
686 HasSubstr("forward referenced IDs have not been defined"));
687 }
688
TEST_F(ValidateData,forward_ref_bad_type)689 TEST_F(ValidateData, forward_ref_bad_type) {
690 std::string str = header_with_addresses + R"(
691 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
692 %uintt = OpTypeInt 32 0
693 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
694 %_ptr_Generic_struct_A = OpTypeFloat 32
695 )";
696 CompileSuccessfully(str.c_str());
697 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
698 EXPECT_THAT(getDiagnosticString(),
699 HasSubstr("Pointer type in OpTypeForwardPointer is not a pointer "
700 "type.\n OpTypeForwardPointer %float Generic\n"));
701 }
702
TEST_F(ValidateData,forward_ref_points_to_non_struct)703 TEST_F(ValidateData, forward_ref_points_to_non_struct) {
704 std::string str = header_with_addresses + R"(
705 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
706 %uintt = OpTypeInt 32 0
707 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
708 %_ptr_Generic_struct_A = OpTypePointer Generic %uintt
709 )";
710 CompileSuccessfully(str.c_str());
711 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
712 EXPECT_THAT(getDiagnosticString(),
713 HasSubstr("Forward pointers must point to a structure"));
714 }
715
TEST_F(ValidateData,struct_forward_pointer_good)716 TEST_F(ValidateData, struct_forward_pointer_good) {
717 std::string str = header_with_addresses + R"(
718 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
719 %uintt = OpTypeInt 32 0
720 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
721 %struct_C = OpTypeStruct %uintt %struct_B
722 %struct_A = OpTypeStruct %uintt %struct_C
723 %_ptr_Generic_struct_A = OpTypePointer Generic %struct_C
724 )";
725 CompileSuccessfully(str.c_str());
726 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
727 }
728
TEST_F(ValidateData,ext_16bit_storage_caps_allow_free_fp_rounding_mode)729 TEST_F(ValidateData, ext_16bit_storage_caps_allow_free_fp_rounding_mode) {
730 for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16"}) {
731 for (const char* mode : {"RTE", "RTZ", "RTP", "RTN"}) {
732 std::string str = std::string(R"(
733 OpCapability Shader
734 OpCapability Linkage
735 OpCapability )") +
736 cap + R"(
737 OpExtension "SPV_KHR_storage_buffer_storage_class"
738 OpExtension "SPV_KHR_variable_pointers"
739 OpExtension "SPV_KHR_16bit_storage"
740 OpMemoryModel Logical GLSL450
741 OpDecorate %_ FPRoundingMode )" + mode + R"(
742 %half = OpTypeFloat 16
743 %float = OpTypeFloat 32
744 %float_1_25 = OpConstant %float 1.25
745 %half_ptr = OpTypePointer StorageBuffer %half
746 %half_ptr_var = OpVariable %half_ptr StorageBuffer
747 %void = OpTypeVoid
748 %func = OpTypeFunction %void
749 %main = OpFunction %void None %func
750 %main_entry = OpLabel
751 %_ = OpFConvert %half %float_1_25
752 OpStore %half_ptr_var %_
753 OpReturn
754 OpFunctionEnd
755 )";
756 CompileSuccessfully(str.c_str());
757 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
758 }
759 }
760 }
761
TEST_F(ValidateData,vulkan_disallow_free_fp_rounding_mode)762 TEST_F(ValidateData, vulkan_disallow_free_fp_rounding_mode) {
763 for (const char* mode : {"RTE", "RTZ"}) {
764 for (const auto env : {SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
765 std::string str = std::string(R"(
766 OpCapability Shader
767 OpExtension "SPV_KHR_storage_buffer_storage_class"
768 OpExtension "SPV_KHR_variable_pointers"
769 OpMemoryModel Logical GLSL450
770 OpDecorate %_ FPRoundingMode )") +
771 mode + R"(
772 %half = OpTypeFloat 16
773 %float = OpTypeFloat 32
774 %float_1_25 = OpConstant %float 1.25
775 %half_ptr = OpTypePointer StorageBuffer %half
776 %half_ptr_var = OpVariable %half_ptr StorageBuffer
777 %void = OpTypeVoid
778 %func = OpTypeFunction %void
779 %main = OpFunction %void None %func
780 %main_entry = OpLabel
781 %_ = OpFConvert %half %float_1_25
782 OpStore %half_ptr_var %_
783 OpReturn
784 OpFunctionEnd
785 )";
786 CompileSuccessfully(str.c_str());
787 ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(env));
788 EXPECT_THAT(
789 getDiagnosticString(),
790 HasSubstr(
791 "Operand 2 of Decorate requires one of these capabilities: "
792 "StorageBuffer16BitAccess UniformAndStorageBuffer16BitAccess "
793 "StoragePushConstant16 StorageInputOutput16"));
794 }
795 }
796 }
797
TEST_F(ValidateData,void_array)798 TEST_F(ValidateData, void_array) {
799 std::string str = header + R"(
800 %void = OpTypeVoid
801 %int = OpTypeInt 32 0
802 %int_5 = OpConstant %int 5
803 %array = OpTypeArray %void %int_5
804 )";
805
806 CompileSuccessfully(str.c_str());
807 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
808 EXPECT_THAT(
809 getDiagnosticString(),
810 HasSubstr("OpTypeArray Element Type <id> '1[%void]' is a void type."));
811 }
812
TEST_F(ValidateData,void_runtime_array)813 TEST_F(ValidateData, void_runtime_array) {
814 std::string str = header + R"(
815 %void = OpTypeVoid
816 %array = OpTypeRuntimeArray %void
817 )";
818
819 CompileSuccessfully(str.c_str());
820 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
821 EXPECT_THAT(
822 getDiagnosticString(),
823 HasSubstr(
824 "OpTypeRuntimeArray Element Type <id> '1[%void]' is a void type."));
825 }
826
TEST_F(ValidateData,vulkan_RTA_array_at_end_of_struct)827 TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) {
828 std::string str = R"(
829 OpCapability Shader
830 OpMemoryModel Logical GLSL450
831 OpEntryPoint Fragment %func "func"
832 OpExecutionMode %func OriginUpperLeft
833 OpDecorate %array_t ArrayStride 4
834 OpMemberDecorate %struct_t 0 Offset 0
835 OpMemberDecorate %struct_t 1 Offset 4
836 OpDecorate %struct_t Block
837 %uint_t = OpTypeInt 32 0
838 %array_t = OpTypeRuntimeArray %uint_t
839 %struct_t = OpTypeStruct %uint_t %array_t
840 %struct_ptr = OpTypePointer StorageBuffer %struct_t
841 %2 = OpVariable %struct_ptr StorageBuffer
842 %void = OpTypeVoid
843 %func_t = OpTypeFunction %void
844 %func = OpFunction %void None %func_t
845 %1 = OpLabel
846 OpReturn
847 OpFunctionEnd
848 )";
849
850 CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
851 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
852 }
853
TEST_F(ValidateData,vulkan_RTA_not_at_end_of_struct)854 TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) {
855 std::string str = R"(
856 OpCapability Shader
857 OpMemoryModel Logical GLSL450
858 OpEntryPoint Fragment %func "func"
859 OpExecutionMode %func OriginUpperLeft
860 OpDecorate %array_t ArrayStride 4
861 OpMemberDecorate %struct_t 0 Offset 0
862 OpMemberDecorate %struct_t 1 Offset 4
863 OpDecorate %struct_t Block
864 %uint_t = OpTypeInt 32 0
865 %array_t = OpTypeRuntimeArray %uint_t
866 %struct_t = OpTypeStruct %array_t %uint_t
867 %struct_ptr = OpTypePointer StorageBuffer %struct_t
868 %2 = OpVariable %struct_ptr StorageBuffer
869 %void = OpTypeVoid
870 %func_t = OpTypeFunction %void
871 %func = OpFunction %void None %func_t
872 %1 = OpLabel
873 OpReturn
874 OpFunctionEnd
875 )";
876
877 CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
878 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
879 EXPECT_THAT(getDiagnosticString(),
880 HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for "
881 "the last member of an OpTypeStruct\n %_struct_3 = "
882 "OpTypeStruct %_runtimearr_uint %uint\n"));
883 }
884
TEST_F(ValidateData,webgpu_RTA_array_at_end_of_struct)885 TEST_F(ValidateData, webgpu_RTA_array_at_end_of_struct) {
886 std::string str = R"(
887 OpCapability Shader
888 OpCapability VulkanMemoryModelKHR
889 OpExtension "SPV_KHR_vulkan_memory_model"
890 OpMemoryModel Logical VulkanKHR
891 OpEntryPoint Fragment %func "func"
892 OpExecutionMode %func OriginUpperLeft
893 OpDecorate %array_t ArrayStride 4
894 OpMemberDecorate %struct_t 0 Offset 0
895 OpMemberDecorate %struct_t 1 Offset 4
896 OpDecorate %struct_t Block
897 %uint_t = OpTypeInt 32 0
898 %array_t = OpTypeRuntimeArray %uint_t
899 %struct_t = OpTypeStruct %uint_t %array_t
900 %struct_ptr = OpTypePointer StorageBuffer %struct_t
901 %2 = OpVariable %struct_ptr StorageBuffer
902 %void = OpTypeVoid
903 %func_t = OpTypeFunction %void
904 %func = OpFunction %void None %func_t
905 %1 = OpLabel
906 OpReturn
907 OpFunctionEnd
908 )";
909
910 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
911 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
912 }
913
TEST_F(ValidateData,webgpu_RTA_not_at_end_of_struct)914 TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) {
915 std::string str = R"(
916 OpCapability Shader
917 OpCapability VulkanMemoryModelKHR
918 OpExtension "SPV_KHR_vulkan_memory_model"
919 OpMemoryModel Logical VulkanKHR
920 OpEntryPoint Fragment %func "func"
921 OpExecutionMode %func OriginUpperLeft
922 OpDecorate %array_t ArrayStride 4
923 OpMemberDecorate %struct_t 0 Offset 0
924 OpMemberDecorate %struct_t 1 Offset 4
925 OpDecorate %struct_t Block
926 %uint_t = OpTypeInt 32 0
927 %array_t = OpTypeRuntimeArray %uint_t
928 %struct_t = OpTypeStruct %array_t %uint_t
929 %struct_ptr = OpTypePointer StorageBuffer %struct_t
930 %2 = OpVariable %struct_ptr StorageBuffer
931 %void = OpTypeVoid
932 %func_t = OpTypeFunction %void
933 %func = OpFunction %void None %func_t
934 %1 = OpLabel
935 OpReturn
936 OpFunctionEnd
937 )";
938
939 CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
940 ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
941 EXPECT_THAT(getDiagnosticString(),
942 HasSubstr("In WebGPU, OpTypeRuntimeArray must only be used for "
943 "the last member of an OpTypeStruct\n %_struct_3 = "
944 "OpTypeStruct %_runtimearr_uint %uint\n"));
945 }
946
947 } // namespace
948 } // namespace val
949 } // namespace spvtools
950