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
24namespace spvtools {
25namespace val {
26namespace {
27
28using ::testing::HasSubstr;
29using ::testing::MatchesRegex;
30
31using ValidateData = spvtest::ValidateBase<std::pair<std::string, bool>>;
32
33std::string HeaderWith(std::string cap) {
34  return std::string("OpCapability Shader OpCapability Linkage OpCapability ") +
35         cap + " OpMemoryModel Logical GLSL450 ";
36}
37
38std::string header = R"(
39     OpCapability Shader
40     OpCapability Linkage
41     OpMemoryModel Logical GLSL450
42)";
43std::string header_with_addresses = R"(
44     OpCapability Addresses
45     OpCapability Kernel
46     OpCapability GenericPointer
47     OpCapability Linkage
48     OpMemoryModel Physical32 OpenCL
49)";
50std::string header_with_vec16_cap = R"(
51     OpCapability Shader
52     OpCapability Vector16
53     OpCapability Linkage
54     OpMemoryModel Logical GLSL450
55)";
56std::string header_with_int8 = R"(
57     OpCapability Shader
58     OpCapability Linkage
59     OpCapability Int8
60     OpMemoryModel Logical GLSL450
61)";
62std::string header_with_int16 = R"(
63     OpCapability Shader
64     OpCapability Linkage
65     OpCapability Int16
66     OpMemoryModel Logical GLSL450
67)";
68std::string header_with_int64 = R"(
69     OpCapability Shader
70     OpCapability Linkage
71     OpCapability Int64
72     OpMemoryModel Logical GLSL450
73)";
74std::string header_with_float16 = R"(
75     OpCapability Shader
76     OpCapability Linkage
77     OpCapability Float16
78     OpMemoryModel Logical GLSL450
79)";
80std::string header_with_float16_buffer = R"(
81     OpCapability Shader
82     OpCapability Linkage
83     OpCapability Float16Buffer
84     OpMemoryModel Logical GLSL450
85)";
86std::string header_with_float64 = R"(
87     OpCapability Shader
88     OpCapability Linkage
89     OpCapability Float64
90     OpMemoryModel Logical GLSL450
91)";
92
93std::string invalid_comp_error = "Illegal number of components";
94std::string missing_cap_error = "requires the Vector16 capability";
95std::string missing_int8_cap_error = "requires the Int8 capability";
96std::string missing_int16_cap_error =
97    "requires the Int16 capability,"
98    " or an extension that explicitly enables 16-bit integers.";
99std::string missing_int64_cap_error = "requires the Int64 capability";
100std::string missing_float16_cap_error =
101    "requires the Float16 or Float16Buffer capability,"
102    " or an extension that explicitly enables 16-bit floating point.";
103std::string missing_float64_cap_error = "requires the Float64 capability";
104std::string invalid_num_bits_error = "Invalid number of bits";
105
106TEST_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
116TEST_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
126TEST_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
135TEST_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
144TEST_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
153TEST_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
163TEST_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
173TEST_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
182TEST_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
192TEST_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
201TEST_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
211TEST_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
217TEST_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
224TEST_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
233TEST_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
242TEST_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
251TEST_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
257TEST_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
266TEST_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
274TEST_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
283TEST_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
292TEST_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
303TEST_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
310TEST_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
316TEST_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}
324TEST_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
331TEST_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
337TEST_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
343TEST_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
350TEST_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
356TEST_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}
364TEST_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
371TEST_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
381TEST_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
392TEST_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
403TEST_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
415TEST_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
427TEST_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
440TEST_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
453TEST_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
463TEST_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
473TEST_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
483TEST_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
496TEST_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
504TEST_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
512TEST_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
521TEST_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
532TEST_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
543TEST_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
554TEST_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
566TEST_F(ValidateData, forward_pointer_missing_definition) {
567  std::string str = header_with_addresses + R"(
568OpTypeForwardPointer %_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
578TEST_F(ValidateData, forward_ref_bad_type) {
579  std::string str = header_with_addresses + R"(
580OpTypeForwardPointer %_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
592TEST_F(ValidateData, forward_ref_points_to_non_struct) {
593  std::string str = header_with_addresses + R"(
594OpTypeForwardPointer %_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
605TEST_F(ValidateData, struct_forward_pointer_good) {
606  std::string str = header_with_addresses + R"(
607OpTypeForwardPointer %_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
618TEST_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
651TEST_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
687TEST_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
702TEST_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
716TEST_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
743TEST_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
776TEST_F(ValidateData, TypeForwardReference) {
777  std::string test = R"(
778OpCapability Shader
779OpCapability PhysicalStorageBufferAddresses
780OpCapability Linkage
781OpMemoryModel Logical GLSL450
782OpTypeForwardPointer %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
792TEST_F(ValidateData, VulkanTypeForwardStorageClass) {
793  std::string test = R"(
794OpCapability Shader
795OpCapability PhysicalStorageBufferAddresses
796OpMemoryModel Logical GLSL450
797OpTypeForwardPointer %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
812TEST_F(ValidateData, TypeForwardReferenceMustBeForwardPointer) {
813  std::string test = R"(
814OpCapability Shader
815OpCapability PhysicalStorageBufferAddresses
816OpCapability Linkage
817OpMemoryModel 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