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