• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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