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