1 // Copyright (c) 2017 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 #include <sstream>
16 #include <string>
17 
18 #include "gmock/gmock.h"
19 #include "test/unit_spirv.h"
20 #include "test/val/val_code_generator.h"
21 #include "test/val/val_fixtures.h"
22 
23 namespace spvtools {
24 namespace val {
25 namespace {
26 
27 using ::testing::HasSubstr;
28 using ::testing::Not;
29 using ::testing::Values;
30 
31 using ValidateComposites = spvtest::ValidateBase<bool>;
32 
GenerateShaderCode(const std::string & body,const std::string & capabilities_and_extensions="",const std::string & execution_model="Fragment")33 std::string GenerateShaderCode(
34     const std::string& body,
35     const std::string& capabilities_and_extensions = "",
36     const std::string& execution_model = "Fragment") {
37   std::ostringstream ss;
38   ss << R"(
39 OpCapability Shader
40 OpCapability Float64
41 )";
42 
43   ss << capabilities_and_extensions;
44   ss << "OpMemoryModel Logical GLSL450\n";
45   ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
46   if (execution_model == "Fragment") {
47     ss << "OpExecutionMode %main OriginUpperLeft\n";
48   }
49 
50   ss << R"(
51 %void = OpTypeVoid
52 %func = OpTypeFunction %void
53 %bool = OpTypeBool
54 %f32 = OpTypeFloat 32
55 %f64 = OpTypeFloat 64
56 %u32 = OpTypeInt 32 0
57 %s32 = OpTypeInt 32 1
58 %f32vec2 = OpTypeVector %f32 2
59 %f32vec3 = OpTypeVector %f32 3
60 %f32vec4 = OpTypeVector %f32 4
61 %f64vec2 = OpTypeVector %f64 2
62 %u32vec2 = OpTypeVector %u32 2
63 %u32vec4 = OpTypeVector %u32 4
64 %f64mat22 = OpTypeMatrix %f64vec2 2
65 %f32mat22 = OpTypeMatrix %f32vec2 2
66 %f32mat23 = OpTypeMatrix %f32vec2 3
67 %f32mat32 = OpTypeMatrix %f32vec3 2
68 
69 %f32_0 = OpConstant %f32 0
70 %f32_1 = OpConstant %f32 1
71 %f32_2 = OpConstant %f32 2
72 %f32_3 = OpConstant %f32 3
73 %f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1
74 %f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2
75 %f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
76 
77 %u32_0 = OpConstant %u32 0
78 %u32_1 = OpConstant %u32 1
79 %u32_2 = OpConstant %u32 2
80 %u32_3 = OpConstant %u32 3
81 
82 %u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1
83 %u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3
84 
85 %f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12
86 %f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12
87 
88 %f32vec2arr3 = OpTypeArray %f32vec2 %u32_3
89 %f32vec2arr2 = OpTypeArray %f32vec2 %u32_2
90 
91 %f32u32struct = OpTypeStruct %f32 %u32
92 %big_struct = OpTypeStruct %f32 %f32vec4 %f32mat23 %f32vec2arr3 %f32vec2arr2 %f32u32struct
93 
94 %ptr_big_struct = OpTypePointer Uniform %big_struct
95 %var_big_struct = OpVariable %ptr_big_struct Uniform
96 
97 %main = OpFunction %void None %func
98 %main_entry = OpLabel
99 )";
100 
101   ss << body;
102 
103   ss << R"(
104 OpReturn
105 OpFunctionEnd)";
106 
107   return ss.str();
108 }
109 
110 // Returns header for legacy tests taken from val_id_test.cpp.
GetHeaderForTestsFromValId()111 std::string GetHeaderForTestsFromValId() {
112   return R"(
113 OpCapability Shader
114 OpCapability Linkage
115 OpCapability Addresses
116 OpCapability Pipes
117 OpCapability LiteralSampler
118 OpCapability DeviceEnqueue
119 OpCapability Vector16
120 OpCapability Int8
121 OpCapability Int16
122 OpCapability Int64
123 OpCapability Float64
124 OpMemoryModel Logical GLSL450
125 %void = OpTypeVoid
126 %void_f  = OpTypeFunction %void
127 %int = OpTypeInt 32 0
128 %float = OpTypeFloat 32
129 %v3float = OpTypeVector %float 3
130 %mat4x3 = OpTypeMatrix %v3float 4
131 %_ptr_Private_mat4x3 = OpTypePointer Private %mat4x3
132 %_ptr_Private_float = OpTypePointer Private %float
133 %my_matrix = OpVariable %_ptr_Private_mat4x3 Private
134 %my_float_var = OpVariable %_ptr_Private_float Private
135 %_ptr_Function_float = OpTypePointer Function %float
136 %int_0 = OpConstant %int 0
137 %int_1 = OpConstant %int 1
138 %int_2 = OpConstant %int 2
139 %int_3 = OpConstant %int 3
140 %int_5 = OpConstant %int 5
141 
142 ; Making the following nested structures.
143 ;
144 ; struct S {
145 ;   bool b;
146 ;   vec4 v[5];
147 ;   int i;
148 ;   mat4x3 m[5];
149 ; }
150 ; uniform blockName {
151 ;   S s;
152 ;   bool cond;
153 ; }
154 
155 %f32arr = OpTypeRuntimeArray %float
156 %v4float = OpTypeVector %float 4
157 %array5_mat4x3 = OpTypeArray %mat4x3 %int_5
158 %array5_vec4 = OpTypeArray %v4float %int_5
159 %_ptr_Uniform_float = OpTypePointer Uniform %float
160 %_ptr_Function_vec4 = OpTypePointer Function %v4float
161 %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float
162 %struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3
163 %struct_blockName = OpTypeStruct %struct_s %int
164 %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName
165 %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s
166 %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3
167 %_ptr_Uniform_mat4x3 = OpTypePointer Uniform %mat4x3
168 %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
169 %blockName_var = OpVariable %_ptr_Uniform_blockName Uniform
170 %spec_int = OpSpecConstant %int 2
171 %func = OpFunction %void None %void_f
172 %my_label = OpLabel
173 )";
174 }
175 
TEST_F(ValidateComposites,VectorExtractDynamicSuccess)176 TEST_F(ValidateComposites, VectorExtractDynamicSuccess) {
177   const std::string body = R"(
178 %val1 = OpVectorExtractDynamic %f32 %f32vec4_0123 %u32_0
179 )";
180 
181   CompileSuccessfully(GenerateShaderCode(body).c_str());
182   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
183 }
184 
TEST_F(ValidateComposites,VectorExtractDynamicWrongResultType)185 TEST_F(ValidateComposites, VectorExtractDynamicWrongResultType) {
186   const std::string body = R"(
187 %val1 = OpVectorExtractDynamic %f32vec4 %f32vec4_0123 %u32_0
188 )";
189 
190   CompileSuccessfully(GenerateShaderCode(body).c_str());
191   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
192   EXPECT_THAT(getDiagnosticString(),
193               HasSubstr("Expected Result Type to be a scalar type"));
194 }
195 
TEST_F(ValidateComposites,VectorExtractDynamicNotVector)196 TEST_F(ValidateComposites, VectorExtractDynamicNotVector) {
197   const std::string body = R"(
198 %val1 = OpVectorExtractDynamic %f32 %f32mat22_1212 %u32_0
199 )";
200 
201   CompileSuccessfully(GenerateShaderCode(body).c_str());
202   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
203   EXPECT_THAT(getDiagnosticString(),
204               HasSubstr("Expected Vector type to be OpTypeVector"));
205 }
206 
TEST_F(ValidateComposites,VectorExtractDynamicWrongVectorComponent)207 TEST_F(ValidateComposites, VectorExtractDynamicWrongVectorComponent) {
208   const std::string body = R"(
209 %val1 = OpVectorExtractDynamic %f32 %u32vec4_0123 %u32_0
210 )";
211 
212   CompileSuccessfully(GenerateShaderCode(body).c_str());
213   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
214   EXPECT_THAT(
215       getDiagnosticString(),
216       HasSubstr("Expected Vector component type to be equal to Result Type"));
217 }
218 
TEST_F(ValidateComposites,VectorExtractDynamicWrongIndexType)219 TEST_F(ValidateComposites, VectorExtractDynamicWrongIndexType) {
220   const std::string body = R"(
221 %val1 = OpVectorExtractDynamic %f32 %f32vec4_0123 %f32_0
222 )";
223 
224   CompileSuccessfully(GenerateShaderCode(body).c_str());
225   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
226   EXPECT_THAT(getDiagnosticString(),
227               HasSubstr("Expected Index to be int scalar"));
228 }
229 
TEST_F(ValidateComposites,VectorInsertDynamicSuccess)230 TEST_F(ValidateComposites, VectorInsertDynamicSuccess) {
231   const std::string body = R"(
232 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %f32_1 %u32_0
233 )";
234 
235   CompileSuccessfully(GenerateShaderCode(body).c_str());
236   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
237 }
238 
TEST_F(ValidateComposites,VectorInsertDynamicWrongResultType)239 TEST_F(ValidateComposites, VectorInsertDynamicWrongResultType) {
240   const std::string body = R"(
241 %val1 = OpVectorInsertDynamic %f32 %f32vec4_0123 %f32_1 %u32_0
242 )";
243 
244   CompileSuccessfully(GenerateShaderCode(body).c_str());
245   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
246   EXPECT_THAT(getDiagnosticString(),
247               HasSubstr("Expected Result Type to be OpTypeVector"));
248 }
249 
TEST_F(ValidateComposites,VectorInsertDynamicNotVector)250 TEST_F(ValidateComposites, VectorInsertDynamicNotVector) {
251   const std::string body = R"(
252 %val1 = OpVectorInsertDynamic %f32vec4 %f32mat22_1212 %f32_1 %u32_0
253 )";
254 
255   CompileSuccessfully(GenerateShaderCode(body).c_str());
256   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
257   EXPECT_THAT(getDiagnosticString(),
258               HasSubstr("Expected Vector type to be equal to Result Type"));
259 }
260 
TEST_F(ValidateComposites,VectorInsertDynamicWrongComponentType)261 TEST_F(ValidateComposites, VectorInsertDynamicWrongComponentType) {
262   const std::string body = R"(
263 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %u32_1 %u32_0
264 )";
265 
266   CompileSuccessfully(GenerateShaderCode(body).c_str());
267   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
268   EXPECT_THAT(getDiagnosticString(),
269               HasSubstr("Expected Component type to be equal to Result Type "
270                         "component type"));
271 }
272 
TEST_F(ValidateComposites,VectorInsertDynamicWrongIndexType)273 TEST_F(ValidateComposites, VectorInsertDynamicWrongIndexType) {
274   const std::string body = R"(
275 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %f32_1 %f32_0
276 )";
277 
278   CompileSuccessfully(GenerateShaderCode(body).c_str());
279   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
280   EXPECT_THAT(getDiagnosticString(),
281               HasSubstr("Expected Index to be int scalar"));
282 }
283 
TEST_F(ValidateComposites,CompositeConstructNotComposite)284 TEST_F(ValidateComposites, CompositeConstructNotComposite) {
285   const std::string body = R"(
286 %val1 = OpCompositeConstruct %f32 %f32_1
287 )";
288 
289   CompileSuccessfully(GenerateShaderCode(body).c_str());
290   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
291   EXPECT_THAT(getDiagnosticString(),
292               HasSubstr("Expected Result Type to be a composite type"));
293 }
294 
TEST_F(ValidateComposites,CompositeConstructVectorSuccess)295 TEST_F(ValidateComposites, CompositeConstructVectorSuccess) {
296   const std::string body = R"(
297 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32vec2_12
298 %val2 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32_0 %f32_0
299 %val3 = OpCompositeConstruct %f32vec4 %f32_0 %f32_0 %f32vec2_12
300 %val4 = OpCompositeConstruct %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
301 )";
302 
303   CompileSuccessfully(GenerateShaderCode(body).c_str());
304   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
305 }
306 
TEST_F(ValidateComposites,CompositeConstructVectorOnlyOneConstituent)307 TEST_F(ValidateComposites, CompositeConstructVectorOnlyOneConstituent) {
308   const std::string body = R"(
309 %val1 = OpCompositeConstruct %f32vec4 %f32vec4_0123
310 )";
311 
312   CompileSuccessfully(GenerateShaderCode(body).c_str());
313   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
314   EXPECT_THAT(getDiagnosticString(),
315               HasSubstr("Expected number of constituents to be at least 2"));
316 }
317 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituent1)318 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent1) {
319   const std::string body = R"(
320 %val1 = OpCompositeConstruct %f32vec4 %f32 %f32vec2_12
321 )";
322 
323   CompileSuccessfully(GenerateShaderCode(body).c_str());
324   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
325   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 5[%float] cannot be a "
326                                                "type"));
327 }
328 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituent2)329 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent2) {
330   const std::string body = R"(
331 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %u32vec2_01
332 )";
333 
334   CompileSuccessfully(GenerateShaderCode(body).c_str());
335   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
336   EXPECT_THAT(
337       getDiagnosticString(),
338       HasSubstr("Expected Constituents to be scalars or vectors of the same "
339                 "type as Result Type components"));
340 }
341 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituent3)342 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent3) {
343   const std::string body = R"(
344 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %u32_0 %f32_0
345 )";
346 
347   CompileSuccessfully(GenerateShaderCode(body).c_str());
348   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
349   EXPECT_THAT(
350       getDiagnosticString(),
351       HasSubstr("Expected Constituents to be scalars or vectors of the same "
352                 "type as Result Type components"));
353 }
354 
TEST_F(ValidateComposites,CompositeConstructVectorWrongComponentNumber1)355 TEST_F(ValidateComposites, CompositeConstructVectorWrongComponentNumber1) {
356   const std::string body = R"(
357 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32_0
358 )";
359 
360   CompileSuccessfully(GenerateShaderCode(body).c_str());
361   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
362   EXPECT_THAT(
363       getDiagnosticString(),
364       HasSubstr("Expected total number of given components to be equal to the "
365                 "size of Result Type vector"));
366 }
367 
TEST_F(ValidateComposites,CompositeConstructVectorWrongComponentNumber2)368 TEST_F(ValidateComposites, CompositeConstructVectorWrongComponentNumber2) {
369   const std::string body = R"(
370 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32vec2_12 %f32_0
371 )";
372 
373   CompileSuccessfully(GenerateShaderCode(body).c_str());
374   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
375   EXPECT_THAT(
376       getDiagnosticString(),
377       HasSubstr("Expected total number of given components to be equal to the "
378                 "size of Result Type vector"));
379 }
380 
TEST_F(ValidateComposites,CompositeConstructMatrixSuccess)381 TEST_F(ValidateComposites, CompositeConstructMatrixSuccess) {
382   const std::string body = R"(
383 %val1 = OpCompositeConstruct %f32mat22 %f32vec2_12 %f32vec2_12
384 %val2 = OpCompositeConstruct %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12
385 )";
386 
387   CompileSuccessfully(GenerateShaderCode(body).c_str());
388   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
389 }
390 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituentNumber1)391 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituentNumber1) {
392   const std::string body = R"(
393 %val1 = OpCompositeConstruct %f32mat22 %f32vec2_12
394 )";
395 
396   CompileSuccessfully(GenerateShaderCode(body).c_str());
397   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
398   EXPECT_THAT(
399       getDiagnosticString(),
400       HasSubstr("Expected total number of Constituents to be equal to the "
401                 "number of columns of Result Type matrix"));
402 }
403 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituentNumber2)404 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituentNumber2) {
405   const std::string body = R"(
406 %val1 = OpCompositeConstruct %f32mat22 %f32vec2_12 %f32vec2_12 %f32vec2_12
407 )";
408 
409   CompileSuccessfully(GenerateShaderCode(body).c_str());
410   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
411   EXPECT_THAT(
412       getDiagnosticString(),
413       HasSubstr("Expected total number of Constituents to be equal to the "
414                 "number of columns of Result Type matrix"));
415 }
416 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituent)417 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent) {
418   const std::string body = R"(
419 %val1 = OpCompositeConstruct %f32mat22 %f32vec2_12 %u32vec2_01
420 )";
421 
422   CompileSuccessfully(GenerateShaderCode(body).c_str());
423   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
424   EXPECT_THAT(
425       getDiagnosticString(),
426       HasSubstr("Expected Constituent type to be equal to the column type "
427                 "Result Type matrix"));
428 }
429 
TEST_F(ValidateComposites,CompositeConstructArraySuccess)430 TEST_F(ValidateComposites, CompositeConstructArraySuccess) {
431   const std::string body = R"(
432 %val1 = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12
433 )";
434 
435   CompileSuccessfully(GenerateShaderCode(body).c_str());
436   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
437 }
438 
TEST_F(ValidateComposites,CompositeConstructArrayWrongConsituentNumber1)439 TEST_F(ValidateComposites, CompositeConstructArrayWrongConsituentNumber1) {
440   const std::string body = R"(
441 %val1 = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12
442 )";
443 
444   CompileSuccessfully(GenerateShaderCode(body).c_str());
445   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
446   EXPECT_THAT(
447       getDiagnosticString(),
448       HasSubstr("Expected total number of Constituents to be equal to the "
449                 "number of elements of Result Type array"));
450 }
451 
TEST_F(ValidateComposites,CompositeConstructArrayWrongConsituentNumber2)452 TEST_F(ValidateComposites, CompositeConstructArrayWrongConsituentNumber2) {
453   const std::string body = R"(
454 %val1 = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12 %f32vec2_12
455 )";
456 
457   CompileSuccessfully(GenerateShaderCode(body).c_str());
458   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
459   EXPECT_THAT(
460       getDiagnosticString(),
461       HasSubstr("Expected total number of Constituents to be equal to the "
462                 "number of elements of Result Type array"));
463 }
464 
TEST_F(ValidateComposites,CompositeConstructArrayWrongConsituent)465 TEST_F(ValidateComposites, CompositeConstructArrayWrongConsituent) {
466   const std::string body = R"(
467 %val1 = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %u32vec2_01 %f32vec2_12
468 )";
469 
470   CompileSuccessfully(GenerateShaderCode(body).c_str());
471   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
472   EXPECT_THAT(
473       getDiagnosticString(),
474       HasSubstr("Expected Constituent type to be equal to the column type "
475                 "Result Type array"));
476 }
477 
TEST_F(ValidateComposites,CompositeConstructStructSuccess)478 TEST_F(ValidateComposites, CompositeConstructStructSuccess) {
479   const std::string body = R"(
480 %val1 = OpCompositeConstruct %f32u32struct %f32_0 %u32_1
481 )";
482 
483   CompileSuccessfully(GenerateShaderCode(body).c_str());
484   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
485 }
486 
TEST_F(ValidateComposites,CompositeConstructStructWrongConstituentNumber1)487 TEST_F(ValidateComposites, CompositeConstructStructWrongConstituentNumber1) {
488   const std::string body = R"(
489 %val1 = OpCompositeConstruct %f32u32struct %f32_0
490 )";
491 
492   CompileSuccessfully(GenerateShaderCode(body).c_str());
493   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
494   EXPECT_THAT(
495       getDiagnosticString(),
496       HasSubstr("Expected total number of Constituents to be equal to the "
497                 "number of members of Result Type struct"));
498 }
499 
TEST_F(ValidateComposites,CompositeConstructStructWrongConstituentNumber2)500 TEST_F(ValidateComposites, CompositeConstructStructWrongConstituentNumber2) {
501   const std::string body = R"(
502 %val1 = OpCompositeConstruct %f32u32struct %f32_0 %u32_1 %u32_1
503 )";
504 
505   CompileSuccessfully(GenerateShaderCode(body).c_str());
506   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
507   EXPECT_THAT(
508       getDiagnosticString(),
509       HasSubstr("Expected total number of Constituents to be equal to the "
510                 "number of members of Result Type struct"));
511 }
512 
TEST_F(ValidateComposites,CompositeConstructStructWrongConstituent)513 TEST_F(ValidateComposites, CompositeConstructStructWrongConstituent) {
514   const std::string body = R"(
515 %val1 = OpCompositeConstruct %f32u32struct %f32_0 %f32_1
516 )";
517 
518   CompileSuccessfully(GenerateShaderCode(body).c_str());
519   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
520   EXPECT_THAT(getDiagnosticString(),
521               HasSubstr("Expected Constituent type to be equal to the "
522                         "corresponding member type of Result Type struct"));
523 }
524 
TEST_F(ValidateComposites,CopyObjectSuccess)525 TEST_F(ValidateComposites, CopyObjectSuccess) {
526   const std::string body = R"(
527 %val1 = OpCopyObject %f32 %f32_0
528 %val2 = OpCopyObject %f32vec4 %f32vec4_0123
529 )";
530 
531   CompileSuccessfully(GenerateShaderCode(body).c_str());
532   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
533 }
534 
TEST_F(ValidateComposites,CopyObjectResultTypeNotType)535 TEST_F(ValidateComposites, CopyObjectResultTypeNotType) {
536   const std::string body = R"(
537 %val1 = OpCopyObject %f32_0 %f32_0
538 )";
539 
540   CompileSuccessfully(GenerateShaderCode(body).c_str());
541   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
542   EXPECT_THAT(getDiagnosticString(),
543               HasSubstr("ID 19[%float_0] is not a type id"));
544 }
545 
TEST_F(ValidateComposites,CopyObjectWrongOperandType)546 TEST_F(ValidateComposites, CopyObjectWrongOperandType) {
547   const std::string body = R"(
548 %val1 = OpCopyObject %f32 %u32_0
549 )";
550 
551   CompileSuccessfully(GenerateShaderCode(body).c_str());
552   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
553   EXPECT_THAT(
554       getDiagnosticString(),
555       HasSubstr("Expected Result Type and Operand type to be the same"));
556 }
557 
TEST_F(ValidateComposites,TransposeSuccess)558 TEST_F(ValidateComposites, TransposeSuccess) {
559   const std::string body = R"(
560 %val1 = OpTranspose %f32mat32 %f32mat23_121212
561 %val2 = OpTranspose %f32mat22 %f32mat22_1212
562 )";
563 
564   CompileSuccessfully(GenerateShaderCode(body).c_str());
565   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
566 }
567 
TEST_F(ValidateComposites,TransposeResultTypeNotMatrix)568 TEST_F(ValidateComposites, TransposeResultTypeNotMatrix) {
569   const std::string body = R"(
570 %val1 = OpTranspose %f32vec4 %f32mat22_1212
571 )";
572 
573   CompileSuccessfully(GenerateShaderCode(body).c_str());
574   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
575   EXPECT_THAT(getDiagnosticString(),
576               HasSubstr("Expected Result Type to be a matrix type"));
577 }
578 
TEST_F(ValidateComposites,TransposeDifferentComponentTypes)579 TEST_F(ValidateComposites, TransposeDifferentComponentTypes) {
580   const std::string body = R"(
581 %val1 = OpTranspose %f64mat22 %f32mat22_1212
582 )";
583 
584   CompileSuccessfully(GenerateShaderCode(body).c_str());
585   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
586   EXPECT_THAT(
587       getDiagnosticString(),
588       HasSubstr("Expected component types of Matrix and Result Type to be "
589                 "identical"));
590 }
591 
TEST_F(ValidateComposites,TransposeIncompatibleDimensions1)592 TEST_F(ValidateComposites, TransposeIncompatibleDimensions1) {
593   const std::string body = R"(
594 %val1 = OpTranspose %f32mat23 %f32mat22_1212
595 )";
596 
597   CompileSuccessfully(GenerateShaderCode(body).c_str());
598   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
599   EXPECT_THAT(getDiagnosticString(),
600               HasSubstr("Expected number of columns and the column size "
601                         "of Matrix to be the reverse of those of Result Type"));
602 }
603 
TEST_F(ValidateComposites,TransposeIncompatibleDimensions2)604 TEST_F(ValidateComposites, TransposeIncompatibleDimensions2) {
605   const std::string body = R"(
606 %val1 = OpTranspose %f32mat32 %f32mat22_1212
607 )";
608 
609   CompileSuccessfully(GenerateShaderCode(body).c_str());
610   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
611   EXPECT_THAT(getDiagnosticString(),
612               HasSubstr("Expected number of columns and the column size "
613                         "of Matrix to be the reverse of those of Result Type"));
614 }
615 
TEST_F(ValidateComposites,TransposeIncompatibleDimensions3)616 TEST_F(ValidateComposites, TransposeIncompatibleDimensions3) {
617   const std::string body = R"(
618 %val1 = OpTranspose %f32mat23 %f32mat23_121212
619 )";
620 
621   CompileSuccessfully(GenerateShaderCode(body).c_str());
622   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
623   EXPECT_THAT(getDiagnosticString(),
624               HasSubstr("Expected number of columns and the column size "
625                         "of Matrix to be the reverse of those of Result Type"));
626 }
627 
TEST_F(ValidateComposites,CompositeExtractSuccess)628 TEST_F(ValidateComposites, CompositeExtractSuccess) {
629   const std::string body = R"(
630 %val1 = OpCompositeExtract %f32 %f32vec4_0123 1
631 %val2 = OpCompositeExtract %u32 %u32vec4_0123 0
632 %val3 = OpCompositeExtract %f32 %f32mat22_1212 0 1
633 %val4 = OpCompositeExtract %f32vec2 %f32mat22_1212 0
634 %array = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12
635 %val5 = OpCompositeExtract %f32vec2 %array 2
636 %val6 = OpCompositeExtract %f32 %array 2 1
637 %struct = OpLoad %big_struct %var_big_struct
638 %val7 = OpCompositeExtract %f32 %struct 0
639 %val8 = OpCompositeExtract %f32vec4 %struct 1
640 %val9 = OpCompositeExtract %f32 %struct 1 2
641 %val10 = OpCompositeExtract %f32mat23 %struct 2
642 %val11 = OpCompositeExtract %f32vec2 %struct 2 2
643 %val12 = OpCompositeExtract %f32 %struct 2 2 1
644 %val13 = OpCompositeExtract %f32vec2 %struct 3 2
645 %val14 = OpCompositeExtract %f32 %struct 3 2 1
646 %val15 = OpCompositeExtract %f32vec2 %struct 4 1
647 %val16 = OpCompositeExtract %f32 %struct 4 0 1
648 %val17 = OpCompositeExtract %f32 %struct 5 0
649 %val18 = OpCompositeExtract %u32 %struct 5 1
650 )";
651 
652   CompileSuccessfully(GenerateShaderCode(body));
653   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
654 }
655 
TEST_F(ValidateComposites,CompositeExtractNotObject)656 TEST_F(ValidateComposites, CompositeExtractNotObject) {
657   const std::string body = R"(
658 %val1 = OpCompositeExtract %f32 %f32vec4 1
659 )";
660 
661   CompileSuccessfully(GenerateShaderCode(body));
662   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
663   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 11[%v4float] cannot "
664                                                "be a type"));
665 }
666 
TEST_F(ValidateComposites,CompositeExtractNotComposite)667 TEST_F(ValidateComposites, CompositeExtractNotComposite) {
668   const std::string body = R"(
669 %val1 = OpCompositeExtract %f32 %f32_1 0
670 )";
671 
672   CompileSuccessfully(GenerateShaderCode(body));
673   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
674   EXPECT_THAT(getDiagnosticString(),
675               HasSubstr("Reached non-composite type while indexes still remain "
676                         "to be traversed."));
677 }
678 
TEST_F(ValidateComposites,CompositeExtractVectorOutOfBounds)679 TEST_F(ValidateComposites, CompositeExtractVectorOutOfBounds) {
680   const std::string body = R"(
681 %val1 = OpCompositeExtract %f32 %f32vec4_0123 4
682 )";
683 
684   CompileSuccessfully(GenerateShaderCode(body));
685   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
686   EXPECT_THAT(getDiagnosticString(),
687               HasSubstr("Vector access is out of bounds, "
688                         "vector size is 4, but access index is 4"));
689 }
690 
TEST_F(ValidateComposites,CompositeExtractMatrixOutOfCols)691 TEST_F(ValidateComposites, CompositeExtractMatrixOutOfCols) {
692   const std::string body = R"(
693 %val1 = OpCompositeExtract %f32 %f32mat23_121212 3 1
694 )";
695 
696   CompileSuccessfully(GenerateShaderCode(body));
697   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
698   EXPECT_THAT(getDiagnosticString(),
699               HasSubstr("Matrix access is out of bounds, "
700                         "matrix has 3 columns, but access index is 3"));
701 }
702 
TEST_F(ValidateComposites,CompositeExtractMatrixOutOfRows)703 TEST_F(ValidateComposites, CompositeExtractMatrixOutOfRows) {
704   const std::string body = R"(
705 %val1 = OpCompositeExtract %f32 %f32mat23_121212 2 5
706 )";
707 
708   CompileSuccessfully(GenerateShaderCode(body));
709   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
710   EXPECT_THAT(getDiagnosticString(),
711               HasSubstr("Vector access is out of bounds, "
712                         "vector size is 2, but access index is 5"));
713 }
714 
TEST_F(ValidateComposites,CompositeExtractArrayOutOfBounds)715 TEST_F(ValidateComposites, CompositeExtractArrayOutOfBounds) {
716   const std::string body = R"(
717 %array = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12
718 %val1 = OpCompositeExtract %f32vec2 %array 3
719 )";
720 
721   CompileSuccessfully(GenerateShaderCode(body));
722   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
723   EXPECT_THAT(getDiagnosticString(),
724               HasSubstr("Array access is out of bounds, "
725                         "array size is 3, but access index is 3"));
726 }
727 
TEST_F(ValidateComposites,CompositeExtractStructOutOfBounds)728 TEST_F(ValidateComposites, CompositeExtractStructOutOfBounds) {
729   const std::string body = R"(
730 %struct = OpLoad %big_struct %var_big_struct
731 %val1 = OpCompositeExtract %f32 %struct 6
732 )";
733 
734   CompileSuccessfully(GenerateShaderCode(body));
735   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
736   EXPECT_THAT(getDiagnosticString(),
737               HasSubstr("Index is out of bounds, can not find index 6 in the "
738                         "structure <id> '37'. This structure has 6 members. "
739                         "Largest valid index is 5."));
740 }
741 
TEST_F(ValidateComposites,CompositeExtractNestedVectorOutOfBounds)742 TEST_F(ValidateComposites, CompositeExtractNestedVectorOutOfBounds) {
743   const std::string body = R"(
744 %struct = OpLoad %big_struct %var_big_struct
745 %val1 = OpCompositeExtract %f32 %struct 3 1 5
746 )";
747 
748   CompileSuccessfully(GenerateShaderCode(body));
749   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
750   EXPECT_THAT(getDiagnosticString(),
751               HasSubstr("Vector access is out of bounds, "
752                         "vector size is 2, but access index is 5"));
753 }
754 
TEST_F(ValidateComposites,CompositeExtractTooManyIndices)755 TEST_F(ValidateComposites, CompositeExtractTooManyIndices) {
756   const std::string body = R"(
757 %struct = OpLoad %big_struct %var_big_struct
758 %val1 = OpCompositeExtract %f32 %struct 3 1 1 2
759 )";
760 
761   CompileSuccessfully(GenerateShaderCode(body));
762   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
763   EXPECT_THAT(getDiagnosticString(),
764               HasSubstr("Reached non-composite type while "
765                         "indexes still remain to be traversed."));
766 }
767 
TEST_F(ValidateComposites,CompositeExtractNoIndices)768 TEST_F(ValidateComposites, CompositeExtractNoIndices) {
769   const std::string body = R"(
770 %struct = OpLoad %big_struct %var_big_struct
771 %val1 = OpCompositeExtract %big_struct %struct
772 )";
773 
774   CompileSuccessfully(GenerateShaderCode(body));
775   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
776   EXPECT_THAT(getDiagnosticString(),
777               HasSubstr("Expected at least one index to OpCompositeExtract"));
778 }
779 
TEST_F(ValidateComposites,CompositeExtractWrongType1)780 TEST_F(ValidateComposites, CompositeExtractWrongType1) {
781   const std::string body = R"(
782 %struct = OpLoad %big_struct %var_big_struct
783 %val1 = OpCompositeExtract %f32vec2 %struct 3 1 1
784 )";
785 
786   CompileSuccessfully(GenerateShaderCode(body));
787   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
788   EXPECT_THAT(
789       getDiagnosticString(),
790       HasSubstr(
791           "Result type (OpTypeVector) does not match the type that results "
792           "from indexing into the composite (OpTypeFloat)."));
793 }
794 
TEST_F(ValidateComposites,CompositeExtractWrongType2)795 TEST_F(ValidateComposites, CompositeExtractWrongType2) {
796   const std::string body = R"(
797 %struct = OpLoad %big_struct %var_big_struct
798 %val1 = OpCompositeExtract %f32 %struct 3 1
799 )";
800 
801   CompileSuccessfully(GenerateShaderCode(body));
802   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
803   EXPECT_THAT(getDiagnosticString(),
804               HasSubstr("Result type (OpTypeFloat) does not match the type "
805                         "that results from indexing into the composite "
806                         "(OpTypeVector)."));
807 }
808 
TEST_F(ValidateComposites,CompositeExtractWrongType3)809 TEST_F(ValidateComposites, CompositeExtractWrongType3) {
810   const std::string body = R"(
811 %struct = OpLoad %big_struct %var_big_struct
812 %val1 = OpCompositeExtract %f32 %struct 2 1
813 )";
814 
815   CompileSuccessfully(GenerateShaderCode(body));
816   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
817   EXPECT_THAT(getDiagnosticString(),
818               HasSubstr("Result type (OpTypeFloat) does not match the type "
819                         "that results from indexing into the composite "
820                         "(OpTypeVector)."));
821 }
822 
TEST_F(ValidateComposites,CompositeExtractWrongType4)823 TEST_F(ValidateComposites, CompositeExtractWrongType4) {
824   const std::string body = R"(
825 %struct = OpLoad %big_struct %var_big_struct
826 %val1 = OpCompositeExtract %f32 %struct 4 1
827 )";
828 
829   CompileSuccessfully(GenerateShaderCode(body));
830   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
831   EXPECT_THAT(getDiagnosticString(),
832               HasSubstr("Result type (OpTypeFloat) does not match the type "
833                         "that results from indexing into the composite "
834                         "(OpTypeVector)."));
835 }
836 
TEST_F(ValidateComposites,CompositeExtractWrongType5)837 TEST_F(ValidateComposites, CompositeExtractWrongType5) {
838   const std::string body = R"(
839 %struct = OpLoad %big_struct %var_big_struct
840 %val1 = OpCompositeExtract %f32 %struct 5 1
841 )";
842 
843   CompileSuccessfully(GenerateShaderCode(body));
844   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
845   EXPECT_THAT(
846       getDiagnosticString(),
847       HasSubstr(
848           "Result type (OpTypeFloat) does not match the "
849           "type that results from indexing into the composite (OpTypeInt)."));
850 }
851 
TEST_F(ValidateComposites,CompositeInsertSuccess)852 TEST_F(ValidateComposites, CompositeInsertSuccess) {
853   const std::string body = R"(
854 %val1 = OpCompositeInsert %f32vec4 %f32_1 %f32vec4_0123 0
855 %val2 = OpCompositeInsert %u32vec4 %u32_1 %u32vec4_0123 0
856 %val3 = OpCompositeInsert %f32mat22 %f32_2 %f32mat22_1212 0 1
857 %val4 = OpCompositeInsert %f32mat22 %f32vec2_01 %f32mat22_1212 0
858 %array = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12
859 %val5 = OpCompositeInsert %f32vec2arr3 %f32vec2_01 %array 2
860 %val6 = OpCompositeInsert %f32vec2arr3 %f32_3 %array 2 1
861 %struct = OpLoad %big_struct %var_big_struct
862 %val7 = OpCompositeInsert %big_struct %f32_3 %struct 0
863 %val8 = OpCompositeInsert %big_struct %f32vec4_0123 %struct 1
864 %val9 = OpCompositeInsert %big_struct %f32_3 %struct 1 2
865 %val10 = OpCompositeInsert %big_struct %f32mat23_121212 %struct 2
866 %val11 = OpCompositeInsert %big_struct %f32vec2_01 %struct 2 2
867 %val12 = OpCompositeInsert %big_struct %f32_3 %struct 2 2 1
868 %val13 = OpCompositeInsert %big_struct %f32vec2_01 %struct 3 2
869 %val14 = OpCompositeInsert %big_struct %f32_3 %struct 3 2 1
870 %val15 = OpCompositeInsert %big_struct %f32vec2_01 %struct 4 1
871 %val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 0 1
872 %val17 = OpCompositeInsert %big_struct %f32_3 %struct 5 0
873 %val18 = OpCompositeInsert %big_struct %u32_3 %struct 5 1
874 )";
875 
876   CompileSuccessfully(GenerateShaderCode(body));
877   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
878 }
879 
TEST_F(ValidateComposites,CompositeInsertResultTypeDifferentFromComposite)880 TEST_F(ValidateComposites, CompositeInsertResultTypeDifferentFromComposite) {
881   const std::string body = R"(
882 %val1 = OpCompositeInsert %f32 %f32_1 %f32vec4_0123 0
883 )";
884 
885   CompileSuccessfully(GenerateShaderCode(body));
886   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
887   EXPECT_THAT(getDiagnosticString(),
888               HasSubstr("The Result Type must be the same as Composite type in "
889                         "OpCompositeInsert yielding Result Id 5."));
890 }
891 
TEST_F(ValidateComposites,CompositeInsertNotComposite)892 TEST_F(ValidateComposites, CompositeInsertNotComposite) {
893   const std::string body = R"(
894 %val1 = OpCompositeInsert %f32 %f32_1 %f32_0 0
895 )";
896 
897   CompileSuccessfully(GenerateShaderCode(body));
898   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
899   EXPECT_THAT(getDiagnosticString(),
900               HasSubstr("Reached non-composite type while indexes still remain "
901                         "to be traversed."));
902 }
903 
TEST_F(ValidateComposites,CompositeInsertVectorOutOfBounds)904 TEST_F(ValidateComposites, CompositeInsertVectorOutOfBounds) {
905   const std::string body = R"(
906 %val1 = OpCompositeInsert %f32vec4 %f32_1 %f32vec4_0123 4
907 )";
908 
909   CompileSuccessfully(GenerateShaderCode(body));
910   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
911   EXPECT_THAT(getDiagnosticString(),
912               HasSubstr("Vector access is out of bounds, "
913                         "vector size is 4, but access index is 4"));
914 }
915 
TEST_F(ValidateComposites,CompositeInsertMatrixOutOfCols)916 TEST_F(ValidateComposites, CompositeInsertMatrixOutOfCols) {
917   const std::string body = R"(
918 %val1 = OpCompositeInsert %f32mat23 %f32_1 %f32mat23_121212 3 1
919 )";
920 
921   CompileSuccessfully(GenerateShaderCode(body));
922   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
923   EXPECT_THAT(getDiagnosticString(),
924               HasSubstr("Matrix access is out of bounds, "
925                         "matrix has 3 columns, but access index is 3"));
926 }
927 
TEST_F(ValidateComposites,CompositeInsertMatrixOutOfRows)928 TEST_F(ValidateComposites, CompositeInsertMatrixOutOfRows) {
929   const std::string body = R"(
930 %val1 = OpCompositeInsert %f32mat23 %f32_1 %f32mat23_121212 2 5
931 )";
932 
933   CompileSuccessfully(GenerateShaderCode(body));
934   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
935   EXPECT_THAT(getDiagnosticString(),
936               HasSubstr("Vector access is out of bounds, "
937                         "vector size is 2, but access index is 5"));
938 }
939 
TEST_F(ValidateComposites,CompositeInsertArrayOutOfBounds)940 TEST_F(ValidateComposites, CompositeInsertArrayOutOfBounds) {
941   const std::string body = R"(
942 %array = OpCompositeConstruct %f32vec2arr3 %f32vec2_12 %f32vec2_12 %f32vec2_12
943 %val1 = OpCompositeInsert %f32vec2arr3 %f32vec2_01 %array 3
944 )";
945 
946   CompileSuccessfully(GenerateShaderCode(body));
947   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
948   EXPECT_THAT(getDiagnosticString(),
949               HasSubstr("Array access is out of bounds, array "
950                         "size is 3, but access index is 3"));
951 }
952 
TEST_F(ValidateComposites,CompositeInsertStructOutOfBounds)953 TEST_F(ValidateComposites, CompositeInsertStructOutOfBounds) {
954   const std::string body = R"(
955 %struct = OpLoad %big_struct %var_big_struct
956 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 6
957 )";
958 
959   CompileSuccessfully(GenerateShaderCode(body));
960   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
961   EXPECT_THAT(getDiagnosticString(),
962               HasSubstr("Index is out of bounds, can not find index 6 in the "
963                         "structure <id> '37'. This structure has 6 members. "
964                         "Largest valid index is 5."));
965 }
966 
TEST_F(ValidateComposites,CompositeInsertNestedVectorOutOfBounds)967 TEST_F(ValidateComposites, CompositeInsertNestedVectorOutOfBounds) {
968   const std::string body = R"(
969 %struct = OpLoad %big_struct %var_big_struct
970 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 3 1 5
971 )";
972 
973   CompileSuccessfully(GenerateShaderCode(body));
974   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
975   EXPECT_THAT(getDiagnosticString(),
976               HasSubstr("Vector access is out of bounds, "
977                         "vector size is 2, but access index is 5"));
978 }
979 
TEST_F(ValidateComposites,CompositeInsertTooManyIndices)980 TEST_F(ValidateComposites, CompositeInsertTooManyIndices) {
981   const std::string body = R"(
982 %struct = OpLoad %big_struct %var_big_struct
983 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 3 1 1 2
984 )";
985 
986   CompileSuccessfully(GenerateShaderCode(body));
987   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
988   EXPECT_THAT(getDiagnosticString(),
989               HasSubstr("Reached non-composite type while indexes still remain "
990                         "to be traversed."));
991 }
992 
TEST_F(ValidateComposites,CompositeInsertWrongType1)993 TEST_F(ValidateComposites, CompositeInsertWrongType1) {
994   const std::string body = R"(
995 %struct = OpLoad %big_struct %var_big_struct
996 %val1 = OpCompositeInsert %big_struct %f32vec2_01 %struct 3 1 1
997 )";
998 
999   CompileSuccessfully(GenerateShaderCode(body));
1000   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1001   EXPECT_THAT(getDiagnosticString(),
1002               HasSubstr("The Object type (OpTypeVector) does not match the "
1003                         "type that results from indexing into the Composite "
1004                         "(OpTypeFloat)."));
1005 }
1006 
TEST_F(ValidateComposites,CompositeInsertWrongType2)1007 TEST_F(ValidateComposites, CompositeInsertWrongType2) {
1008   const std::string body = R"(
1009 %struct = OpLoad %big_struct %var_big_struct
1010 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 3 1
1011 )";
1012 
1013   CompileSuccessfully(GenerateShaderCode(body));
1014   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1015   EXPECT_THAT(getDiagnosticString(),
1016               HasSubstr("The Object type (OpTypeFloat) does not match the type "
1017                         "that results from indexing into the Composite "
1018                         "(OpTypeVector)."));
1019 }
1020 
TEST_F(ValidateComposites,CompositeInsertWrongType3)1021 TEST_F(ValidateComposites, CompositeInsertWrongType3) {
1022   const std::string body = R"(
1023 %struct = OpLoad %big_struct %var_big_struct
1024 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 2 1
1025 )";
1026 
1027   CompileSuccessfully(GenerateShaderCode(body));
1028   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1029   EXPECT_THAT(getDiagnosticString(),
1030               HasSubstr("The Object type (OpTypeFloat) does not match the type "
1031                         "that results from indexing into the Composite "
1032                         "(OpTypeVector)."));
1033 }
1034 
TEST_F(ValidateComposites,CompositeInsertWrongType4)1035 TEST_F(ValidateComposites, CompositeInsertWrongType4) {
1036   const std::string body = R"(
1037 %struct = OpLoad %big_struct %var_big_struct
1038 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 4 1
1039 )";
1040 
1041   CompileSuccessfully(GenerateShaderCode(body));
1042   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1043   EXPECT_THAT(getDiagnosticString(),
1044               HasSubstr("The Object type (OpTypeFloat) does not match the type "
1045                         "that results from indexing into the Composite "
1046                         "(OpTypeVector)."));
1047 }
1048 
TEST_F(ValidateComposites,CompositeInsertWrongType5)1049 TEST_F(ValidateComposites, CompositeInsertWrongType5) {
1050   const std::string body = R"(
1051 %struct = OpLoad %big_struct %var_big_struct
1052 %val1 = OpCompositeInsert %big_struct %f32_1 %struct 5 1
1053 )";
1054 
1055   CompileSuccessfully(GenerateShaderCode(body));
1056   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1057   EXPECT_THAT(getDiagnosticString(),
1058               HasSubstr("The Object type (OpTypeFloat) does not match the type "
1059                         "that results from indexing into the Composite "
1060                         "(OpTypeInt)."));
1061 }
1062 
1063 // Tests ported from val_id_test.cpp.
1064 
1065 // Valid. Tests both CompositeExtract and CompositeInsert with 255 indexes.
TEST_F(ValidateComposites,CompositeExtractInsertLimitsGood)1066 TEST_F(ValidateComposites, CompositeExtractInsertLimitsGood) {
1067   int depth = 255;
1068   std::string header = GetHeaderForTestsFromValId();
1069   header.erase(header.find("%func"));
1070   std::ostringstream spirv;
1071   spirv << header << std::endl;
1072 
1073   // Build nested structures. Struct 'i' contains struct 'i-1'
1074   spirv << "%s_depth_1 = OpTypeStruct %float\n";
1075   for (int i = 2; i <= depth; ++i) {
1076     spirv << "%s_depth_" << i << " = OpTypeStruct %s_depth_" << i - 1 << "\n";
1077   }
1078 
1079   // Define Pointer and Variable to use for CompositeExtract/Insert.
1080   spirv << "%_ptr_Uniform_deep_struct = OpTypePointer Uniform %s_depth_"
1081         << depth << "\n";
1082   spirv << "%deep_var = OpVariable %_ptr_Uniform_deep_struct Uniform\n";
1083 
1084   // Function Start
1085   spirv << R"(
1086   %func = OpFunction %void None %void_f
1087   %my_label = OpLabel
1088   )";
1089 
1090   // OpCompositeExtract/Insert with 'n' indexes (n = depth)
1091   spirv << "%deep = OpLoad %s_depth_" << depth << " %deep_var" << std::endl;
1092   spirv << "%entry = OpCompositeExtract  %float %deep";
1093   for (int i = 0; i < depth; ++i) {
1094     spirv << " 0";
1095   }
1096   spirv << std::endl;
1097   spirv << "%new_composite = OpCompositeInsert %s_depth_" << depth
1098         << " %entry %deep";
1099   for (int i = 0; i < depth; ++i) {
1100     spirv << " 0";
1101   }
1102   spirv << std::endl;
1103 
1104   // Function end
1105   spirv << R"(
1106     OpReturn
1107     OpFunctionEnd
1108   )";
1109   CompileSuccessfully(spirv.str());
1110   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1111 }
1112 
1113 // Invalid: 256 indexes passed to OpCompositeExtract. Limit is 255.
TEST_F(ValidateComposites,CompositeExtractArgCountExceededLimitBad)1114 TEST_F(ValidateComposites, CompositeExtractArgCountExceededLimitBad) {
1115   std::ostringstream spirv;
1116   spirv << GetHeaderForTestsFromValId() << std::endl;
1117   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1118   spirv << "%entry = OpCompositeExtract %float %matrix";
1119   for (int i = 0; i < 256; ++i) {
1120     spirv << " 0";
1121   }
1122   spirv << R"(
1123     OpReturn
1124     OpFunctionEnd
1125   )";
1126   CompileSuccessfully(spirv.str());
1127   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1128   EXPECT_THAT(getDiagnosticString(),
1129               HasSubstr("The number of indexes in OpCompositeExtract may not "
1130                         "exceed 255. Found 256 indexes."));
1131 }
1132 
1133 // Invalid: 256 indexes passed to OpCompositeInsert. Limit is 255.
TEST_F(ValidateComposites,CompositeInsertArgCountExceededLimitBad)1134 TEST_F(ValidateComposites, CompositeInsertArgCountExceededLimitBad) {
1135   std::ostringstream spirv;
1136   spirv << GetHeaderForTestsFromValId() << std::endl;
1137   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1138   spirv << "%new_composite = OpCompositeInsert %mat4x3 %int_0 %matrix";
1139   for (int i = 0; i < 256; ++i) {
1140     spirv << " 0";
1141   }
1142   spirv << R"(
1143     OpReturn
1144     OpFunctionEnd
1145   )";
1146   CompileSuccessfully(spirv.str());
1147   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1148   EXPECT_THAT(getDiagnosticString(),
1149               HasSubstr("The number of indexes in OpCompositeInsert may not "
1150                         "exceed 255. Found 256 indexes."));
1151 }
1152 
1153 // Invalid: In OpCompositeInsert, result type must be the same as composite type
TEST_F(ValidateComposites,CompositeInsertWrongResultTypeBad)1154 TEST_F(ValidateComposites, CompositeInsertWrongResultTypeBad) {
1155   std::ostringstream spirv;
1156   spirv << GetHeaderForTestsFromValId() << std::endl;
1157   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1158   spirv << "%float_entry = OpCompositeExtract  %float %matrix 0 1" << std::endl;
1159   spirv << "%new_composite = OpCompositeInsert %float %float_entry %matrix 0 1"
1160         << std::endl;
1161   spirv << R"(OpReturn
1162               OpFunctionEnd)";
1163   CompileSuccessfully(spirv.str());
1164   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1165   EXPECT_THAT(getDiagnosticString(),
1166               HasSubstr("The Result Type must be the same as Composite type"));
1167 }
1168 
1169 // Invalid: No Indexes were passed to OpCompositeExtract.
TEST_F(ValidateComposites,CompositeExtractNoIndices2)1170 TEST_F(ValidateComposites, CompositeExtractNoIndices2) {
1171   std::ostringstream spirv;
1172   spirv << GetHeaderForTestsFromValId() << std::endl;
1173   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1174   spirv << "%float_entry = OpCompositeExtract  %mat4x3 %matrix" << std::endl;
1175   spirv << R"(OpReturn
1176               OpFunctionEnd)";
1177   CompileSuccessfully(spirv.str());
1178   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1179   EXPECT_THAT(
1180       getDiagnosticString(),
1181       HasSubstr(
1182           "Expected at least one index to OpCompositeExtract, zero found"));
1183 }
1184 
1185 // Invalid: No Indexes were passed to OpCompositeExtract.
TEST_F(ValidateComposites,CompositeExtractNoIndicesWrongResultType)1186 TEST_F(ValidateComposites, CompositeExtractNoIndicesWrongResultType) {
1187   std::ostringstream spirv;
1188   spirv << GetHeaderForTestsFromValId() << std::endl;
1189   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1190   spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl;
1191   spirv << R"(OpReturn
1192               OpFunctionEnd)";
1193   CompileSuccessfully(spirv.str());
1194   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1195   EXPECT_THAT(
1196       getDiagnosticString(),
1197       HasSubstr(
1198           "Expected at least one index to OpCompositeExtract, zero found"));
1199 }
1200 
1201 // Invalid: No Indices were passed to OpCompositeInsert, and the type of the
1202 // Object<id> argument matches the Composite type.
TEST_F(ValidateComposites,CompositeInsertMissingIndices)1203 TEST_F(ValidateComposites, CompositeInsertMissingIndices) {
1204   std::ostringstream spirv;
1205   spirv << GetHeaderForTestsFromValId() << std::endl;
1206   spirv << "%matrix   = OpLoad %mat4x3 %my_matrix" << std::endl;
1207   spirv << "%matrix_2 = OpLoad %mat4x3 %my_matrix" << std::endl;
1208   spirv << "%new_composite = OpCompositeInsert %mat4x3 %matrix_2 %matrix";
1209   spirv << R"(
1210               OpReturn
1211               OpFunctionEnd)";
1212   CompileSuccessfully(spirv.str());
1213   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1214   EXPECT_THAT(
1215       getDiagnosticString(),
1216       HasSubstr(
1217           "Expected at least one index to OpCompositeInsert, zero found"));
1218 }
1219 
1220 // Invalid: No Indices were passed to OpCompositeInsert, but the type of the
1221 // Object<id> argument does not match the Composite type.
TEST_F(ValidateComposites,CompositeInsertMissingIndices2)1222 TEST_F(ValidateComposites, CompositeInsertMissingIndices2) {
1223   std::ostringstream spirv;
1224   spirv << GetHeaderForTestsFromValId() << std::endl;
1225   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
1226   spirv << "%new_composite = OpCompositeInsert %mat4x3 %int_0 %matrix";
1227   spirv << R"(
1228               OpReturn
1229               OpFunctionEnd)";
1230   CompileSuccessfully(spirv.str());
1231   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1232   EXPECT_THAT(
1233       getDiagnosticString(),
1234       HasSubstr(
1235           "Expected at least one index to OpCompositeInsert, zero found"));
1236 }
1237 
1238 // Valid: Tests that we can index into Struct, Array, Matrix, and Vector!
TEST_F(ValidateComposites,CompositeExtractInsertIndexIntoAllTypesGood)1239 TEST_F(ValidateComposites, CompositeExtractInsertIndexIntoAllTypesGood) {
1240   // indexes that we are passing are: 0, 3, 1, 2, 0
1241   // 0 will select the struct_s within the base struct (blockName)
1242   // 3 will select the Array that contains 5 matrices
1243   // 1 will select the Matrix that is at index 1 of the array
1244   // 2 will select the column (which is a vector) within the matrix at index 2
1245   // 0 will select the element at the index 0 of the vector. (which is a float).
1246   std::ostringstream spirv;
1247   spirv << GetHeaderForTestsFromValId() << R"(
1248     %myblock = OpLoad %struct_blockName %blockName_var
1249     %ss = OpCompositeExtract %struct_s %myblock 0
1250     %sa = OpCompositeExtract %array5_mat4x3 %myblock 0 3
1251     %sm = OpCompositeExtract %mat4x3 %myblock 0 3 1
1252     %sc = OpCompositeExtract %v3float %myblock 0 3 1 2
1253     %fl = OpCompositeExtract %float %myblock 0 3 1 2 0
1254     ;
1255     ; Now let's insert back at different levels...
1256     ;
1257     %b1 = OpCompositeInsert %struct_blockName %ss %myblock 0
1258     %b2 = OpCompositeInsert %struct_blockName %sa %myblock 0 3
1259     %b3 = OpCompositeInsert %struct_blockName %sm %myblock 0 3 1
1260     %b4 = OpCompositeInsert %struct_blockName %sc %myblock 0 3 1 2
1261     %b5 = OpCompositeInsert %struct_blockName %fl %myblock 0 3 1 2 0
1262     OpReturn
1263     OpFunctionEnd
1264   )";
1265 
1266   CompileSuccessfully(spirv.str());
1267   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1268 }
1269 
1270 // Invalid. More indexes are provided than needed for OpCompositeExtract.
TEST_F(ValidateComposites,CompositeExtractReachedScalarBad)1271 TEST_F(ValidateComposites, CompositeExtractReachedScalarBad) {
1272   // indexes that we are passing are: 0, 3, 1, 2, 0
1273   // 0 will select the struct_s within the base struct (blockName)
1274   // 3 will select the Array that contains 5 matrices
1275   // 1 will select the Matrix that is at index 1 of the array
1276   // 2 will select the column (which is a vector) within the matrix at index 2
1277   // 0 will select the element at the index 0 of the vector. (which is a float).
1278   std::ostringstream spirv;
1279   spirv << GetHeaderForTestsFromValId() << R"(
1280     %myblock = OpLoad %struct_blockName %blockName_var
1281     %fl = OpCompositeExtract %float %myblock 0 3 1 2 0 1
1282     OpReturn
1283     OpFunctionEnd
1284   )";
1285 
1286   CompileSuccessfully(spirv.str());
1287   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1288   EXPECT_THAT(getDiagnosticString(),
1289               HasSubstr("Reached non-composite type while indexes still remain "
1290                         "to be traversed."));
1291 }
1292 
1293 // Invalid. More indexes are provided than needed for OpCompositeInsert.
TEST_F(ValidateComposites,CompositeInsertReachedScalarBad)1294 TEST_F(ValidateComposites, CompositeInsertReachedScalarBad) {
1295   // indexes that we are passing are: 0, 3, 1, 2, 0
1296   // 0 will select the struct_s within the base struct (blockName)
1297   // 3 will select the Array that contains 5 matrices
1298   // 1 will select the Matrix that is at index 1 of the array
1299   // 2 will select the column (which is a vector) within the matrix at index 2
1300   // 0 will select the element at the index 0 of the vector. (which is a float).
1301   std::ostringstream spirv;
1302   spirv << GetHeaderForTestsFromValId() << R"(
1303     %myblock = OpLoad %struct_blockName %blockName_var
1304     %fl = OpCompositeExtract %float %myblock 0 3 1 2 0
1305     %b5 = OpCompositeInsert %struct_blockName %fl %myblock 0 3 1 2 0 1
1306     OpReturn
1307     OpFunctionEnd
1308   )";
1309 
1310   CompileSuccessfully(spirv.str());
1311   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1312   EXPECT_THAT(getDiagnosticString(),
1313               HasSubstr("Reached non-composite type while indexes still remain "
1314                         "to be traversed."));
1315 }
1316 
1317 // Invalid. Result type doesn't match the type we get from indexing into
1318 // the composite.
TEST_F(ValidateComposites,CompositeExtractResultTypeDoesntMatchIndexedTypeBad)1319 TEST_F(ValidateComposites,
1320        CompositeExtractResultTypeDoesntMatchIndexedTypeBad) {
1321   // indexes that we are passing are: 0, 3, 1, 2, 0
1322   // 0 will select the struct_s within the base struct (blockName)
1323   // 3 will select the Array that contains 5 matrices
1324   // 1 will select the Matrix that is at index 1 of the array
1325   // 2 will select the column (which is a vector) within the matrix at index 2
1326   // 0 will select the element at the index 0 of the vector. (which is a float).
1327   std::ostringstream spirv;
1328   spirv << GetHeaderForTestsFromValId() << R"(
1329     %myblock = OpLoad %struct_blockName %blockName_var
1330     %fl = OpCompositeExtract %int %myblock 0 3 1 2 0
1331     OpReturn
1332     OpFunctionEnd
1333   )";
1334 
1335   CompileSuccessfully(spirv.str());
1336   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1337   EXPECT_THAT(getDiagnosticString(),
1338               HasSubstr("Result type (OpTypeInt) does not match the type that "
1339                         "results from indexing into the composite "
1340                         "(OpTypeFloat)."));
1341 }
1342 
1343 // Invalid. Given object type doesn't match the type we get from indexing into
1344 // the composite.
TEST_F(ValidateComposites,CompositeInsertObjectTypeDoesntMatchIndexedTypeBad)1345 TEST_F(ValidateComposites, CompositeInsertObjectTypeDoesntMatchIndexedTypeBad) {
1346   // indexes that we are passing are: 0, 3, 1, 2, 0
1347   // 0 will select the struct_s within the base struct (blockName)
1348   // 3 will select the Array that contains 5 matrices
1349   // 1 will select the Matrix that is at index 1 of the array
1350   // 2 will select the column (which is a vector) within the matrix at index 2
1351   // 0 will select the element at the index 0 of the vector. (which is a float).
1352   // We are trying to insert an integer where we should be inserting a float.
1353   std::ostringstream spirv;
1354   spirv << GetHeaderForTestsFromValId() << R"(
1355     %myblock = OpLoad %struct_blockName %blockName_var
1356     %b5 = OpCompositeInsert %struct_blockName %int_0 %myblock 0 3 1 2 0
1357     OpReturn
1358     OpFunctionEnd
1359   )";
1360 
1361   CompileSuccessfully(spirv.str());
1362   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1363   EXPECT_THAT(getDiagnosticString(),
1364               HasSubstr("The Object type (OpTypeInt) does not match the type "
1365                         "that results from indexing into the Composite "
1366                         "(OpTypeFloat)."));
1367 }
1368 
1369 // Invalid. Index into a struct is larger than the number of struct members.
TEST_F(ValidateComposites,CompositeExtractStructIndexOutOfBoundBad)1370 TEST_F(ValidateComposites, CompositeExtractStructIndexOutOfBoundBad) {
1371   // struct_blockName has 3 members (index 0,1,2). We'll try to access index 3.
1372   std::ostringstream spirv;
1373   spirv << GetHeaderForTestsFromValId() << R"(
1374     %myblock = OpLoad %struct_blockName %blockName_var
1375     %ss = OpCompositeExtract %struct_s %myblock 3
1376     OpReturn
1377     OpFunctionEnd
1378   )";
1379 
1380   CompileSuccessfully(spirv.str());
1381   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1382   EXPECT_THAT(getDiagnosticString(),
1383               HasSubstr("Index is out of bounds, can not find index 3 in the "
1384                         "structure <id> '25'. This structure has 2 members. "
1385                         "Largest valid index is 1."));
1386 }
1387 
1388 // Invalid. Index into a struct is larger than the number of struct members.
TEST_F(ValidateComposites,CompositeInsertStructIndexOutOfBoundBad)1389 TEST_F(ValidateComposites, CompositeInsertStructIndexOutOfBoundBad) {
1390   // struct_blockName has 3 members (index 0,1,2). We'll try to access index 3.
1391   std::ostringstream spirv;
1392   spirv << GetHeaderForTestsFromValId() << R"(
1393     %myblock = OpLoad %struct_blockName %blockName_var
1394     %ss = OpCompositeExtract %struct_s %myblock 0
1395     %new_composite = OpCompositeInsert %struct_blockName %ss %myblock 3
1396     OpReturn
1397     OpFunctionEnd
1398   )";
1399 
1400   CompileSuccessfully(spirv.str());
1401   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1402   EXPECT_THAT(
1403       getDiagnosticString(),
1404       HasSubstr("Index is out of bounds, can not find index 3 in the structure "
1405                 "<id> '25'. This structure has 2 members. Largest valid index "
1406                 "is 1."));
1407 }
1408 
1409 // #1403: Ensure that the default spec constant value is not used to check the
1410 // extract index.
TEST_F(ValidateComposites,ExtractFromSpecConstantSizedArray)1411 TEST_F(ValidateComposites, ExtractFromSpecConstantSizedArray) {
1412   std::string spirv = R"(
1413 OpCapability Kernel
1414 OpCapability Linkage
1415 OpMemoryModel Logical OpenCL
1416 OpDecorate %spec_const SpecId 1
1417 %void = OpTypeVoid
1418 %uint = OpTypeInt 32 0
1419 %spec_const = OpSpecConstant %uint 3
1420 %uint_array = OpTypeArray %uint %spec_const
1421 %undef = OpUndef %uint_array
1422 %voidf = OpTypeFunction %void
1423 %func = OpFunction %void None %voidf
1424 %1 = OpLabel
1425 %2 = OpCompositeExtract %uint %undef 4
1426 OpReturn
1427 OpFunctionEnd
1428 )";
1429 
1430   CompileSuccessfully(spirv);
1431   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1432 }
1433 
1434 // #1403: Ensure that spec constant ops do not produce false positives.
TEST_F(ValidateComposites,ExtractFromSpecConstantOpSizedArray)1435 TEST_F(ValidateComposites, ExtractFromSpecConstantOpSizedArray) {
1436   std::string spirv = R"(
1437 OpCapability Kernel
1438 OpCapability Linkage
1439 OpMemoryModel Logical OpenCL
1440 OpDecorate %spec_const SpecId 1
1441 %void = OpTypeVoid
1442 %uint = OpTypeInt 32 0
1443 %const = OpConstant %uint 1
1444 %spec_const = OpSpecConstant %uint 3
1445 %spec_const_op = OpSpecConstantOp %uint IAdd %spec_const %const
1446 %uint_array = OpTypeArray %uint %spec_const_op
1447 %undef = OpUndef %uint_array
1448 %voidf = OpTypeFunction %void
1449 %func = OpFunction %void None %voidf
1450 %1 = OpLabel
1451 %2 = OpCompositeExtract %uint %undef 4
1452 OpReturn
1453 OpFunctionEnd
1454 )";
1455 
1456   CompileSuccessfully(spirv);
1457   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1458 }
1459 
1460 // #1403: Ensure that the default spec constant value is not used to check the
1461 // size of the array for a composite construct. This code has limited actual
1462 // value as it is incorrect unless the specialization constant is assigned the
1463 // value of 2, but it is still a valid module.
TEST_F(ValidateComposites,CompositeConstructSpecConstantSizedArray)1464 TEST_F(ValidateComposites, CompositeConstructSpecConstantSizedArray) {
1465   std::string spirv = R"(
1466 OpCapability Kernel
1467 OpCapability Linkage
1468 OpMemoryModel Logical OpenCL
1469 OpDecorate %spec_const SpecId 1
1470 %void = OpTypeVoid
1471 %uint = OpTypeInt 32 0
1472 %uint_0 = OpConstant %uint 0
1473 %spec_const = OpSpecConstant %uint 3
1474 %uint_array = OpTypeArray %uint %spec_const
1475 %voidf = OpTypeFunction %void
1476 %func = OpFunction %void None %voidf
1477 %1 = OpLabel
1478 %2 = OpCompositeConstruct %uint_array %uint_0 %uint_0
1479 OpReturn
1480 OpFunctionEnd
1481 )";
1482 
1483   CompileSuccessfully(spirv);
1484   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1485 }
1486 
TEST_F(ValidateComposites,CoopMatConstantCompositeMismatchFail)1487 TEST_F(ValidateComposites, CoopMatConstantCompositeMismatchFail) {
1488   const std::string body =
1489       R"(
1490 OpCapability Shader
1491 OpCapability Float16
1492 OpCapability CooperativeMatrixNV
1493 OpExtension "SPV_NV_cooperative_matrix"
1494 OpMemoryModel Logical GLSL450
1495 OpEntryPoint GLCompute %main "main"
1496 %void = OpTypeVoid
1497 %func = OpTypeFunction %void
1498 %bool = OpTypeBool
1499 %f16 = OpTypeFloat 16
1500 %f32 = OpTypeFloat 32
1501 %u32 = OpTypeInt 32 0
1502 
1503 %u32_8 = OpConstant %u32 8
1504 %subgroup = OpConstant %u32 3
1505 
1506 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1507 
1508 %f32_1 = OpConstant %f32 1
1509 
1510 %f16mat_1 = OpConstantComposite %f16mat %f32_1
1511 
1512 %main = OpFunction %void None %func
1513 %main_entry = OpLabel
1514 
1515 OpReturn
1516 OpFunctionEnd)";
1517 
1518   CompileSuccessfully(body.c_str());
1519   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1520   EXPECT_THAT(
1521       getDiagnosticString(),
1522       HasSubstr("OpConstantComposite Constituent <id> '11[%float_1]' type does "
1523                 "not match the Result Type <id> '10[%10]'s component type."));
1524 }
1525 
TEST_F(ValidateComposites,CoopMatCompositeConstructMismatchFail)1526 TEST_F(ValidateComposites, CoopMatCompositeConstructMismatchFail) {
1527   const std::string body =
1528       R"(
1529 OpCapability Shader
1530 OpCapability Float16
1531 OpCapability CooperativeMatrixNV
1532 OpExtension "SPV_NV_cooperative_matrix"
1533 OpMemoryModel Logical GLSL450
1534 OpEntryPoint GLCompute %main "main"
1535 %void = OpTypeVoid
1536 %func = OpTypeFunction %void
1537 %bool = OpTypeBool
1538 %f16 = OpTypeFloat 16
1539 %f32 = OpTypeFloat 32
1540 %u32 = OpTypeInt 32 0
1541 
1542 %u32_8 = OpConstant %u32 8
1543 %subgroup = OpConstant %u32 3
1544 
1545 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1546 
1547 %f32_1 = OpConstant %f32 1
1548 
1549 %main = OpFunction %void None %func
1550 %main_entry = OpLabel
1551 
1552 %f16mat_1 = OpCompositeConstruct %f16mat %f32_1
1553 
1554 OpReturn
1555 OpFunctionEnd)";
1556 
1557   CompileSuccessfully(body.c_str());
1558   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1559   EXPECT_THAT(
1560       getDiagnosticString(),
1561       HasSubstr("Expected Constituent type to be equal to the component type"));
1562 }
1563 
TEST_F(ValidateComposites,ExtractDynamicLabelIndex)1564 TEST_F(ValidateComposites, ExtractDynamicLabelIndex) {
1565   const std::string spirv = R"(
1566 OpCapability Shader
1567 OpCapability Linkage
1568 OpMemoryModel Logical GLSL450
1569 %void = OpTypeVoid
1570 %float = OpTypeFloat 32
1571 %v4float = OpTypeVector %float 4
1572 %void_fn = OpTypeFunction %void
1573 %float_0 = OpConstant %float 0
1574 %v4float_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1575 %func = OpFunction %void None %void_fn
1576 %1 = OpLabel
1577 %ex = OpVectorExtractDynamic %float %v4float_0 %v4float_0
1578 OpReturn
1579 OpFunctionEnd
1580 )";
1581 
1582   CompileSuccessfully(spirv);
1583   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1584   EXPECT_THAT(getDiagnosticString(),
1585               HasSubstr("Expected Index to be int scalar"));
1586 }
1587 
TEST_F(ValidateComposites,CopyLogicalSameType)1588 TEST_F(ValidateComposites, CopyLogicalSameType) {
1589   const std::string spirv = R"(
1590 OpCapability Shader
1591 OpCapability Linkage
1592 OpMemoryModel Logical GLSL450
1593 %void = OpTypeVoid
1594 %struct = OpTypeStruct
1595 %const_struct = OpConstantComposite %struct
1596 %void_fn = OpTypeFunction %void
1597 %func = OpFunction %void None %void_fn
1598 %1 = OpLabel
1599 %copy = OpCopyLogical %struct %const_struct
1600 OpReturn
1601 OpFunctionEnd
1602 )";
1603 
1604   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1605   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1606   EXPECT_THAT(getDiagnosticString(),
1607               HasSubstr("Result Type must not equal the Operand type"));
1608 }
1609 
TEST_F(ValidateComposites,CopyLogicalSameStructDifferentId)1610 TEST_F(ValidateComposites, CopyLogicalSameStructDifferentId) {
1611   const std::string spirv = R"(
1612 OpCapability Shader
1613 OpCapability Linkage
1614 OpMemoryModel Logical GLSL450
1615 %void = OpTypeVoid
1616 %struct1 = OpTypeStruct
1617 %struct2 = OpTypeStruct
1618 %const_struct = OpConstantComposite %struct1
1619 %void_fn = OpTypeFunction %void
1620 %func = OpFunction %void None %void_fn
1621 %1 = OpLabel
1622 %copy = OpCopyLogical %struct2 %const_struct
1623 OpReturn
1624 OpFunctionEnd
1625 )";
1626 
1627   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1628   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1629 }
1630 
TEST_F(ValidateComposites,CopyLogicalArrayDifferentLength)1631 TEST_F(ValidateComposites, CopyLogicalArrayDifferentLength) {
1632   const std::string spirv = R"(
1633 OpCapability Shader
1634 OpCapability Linkage
1635 OpMemoryModel Logical GLSL450
1636 %void = OpTypeVoid
1637 %int = OpTypeInt 32 0
1638 %int_4 = OpConstant %int 4
1639 %int_5 = OpConstant %int 5
1640 %array1 = OpTypeArray %int %int_4
1641 %array2 = OpTypeArray %int %int_5
1642 %const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4
1643 %void_fn = OpTypeFunction %void
1644 %func = OpFunction %void None %void_fn
1645 %1 = OpLabel
1646 %copy = OpCopyLogical %array2 %const_array
1647 OpReturn
1648 OpFunctionEnd
1649 )";
1650 
1651   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1652   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1653   EXPECT_THAT(
1654       getDiagnosticString(),
1655       HasSubstr("Result Type does not logically match the Operand type"));
1656 }
1657 
TEST_F(ValidateComposites,CopyLogicalArrayDifferentElement)1658 TEST_F(ValidateComposites, CopyLogicalArrayDifferentElement) {
1659   const std::string spirv = R"(
1660 OpCapability Shader
1661 OpCapability Linkage
1662 OpMemoryModel Logical GLSL450
1663 %void = OpTypeVoid
1664 %float = OpTypeFloat 32
1665 %int = OpTypeInt 32 0
1666 %int_4 = OpConstant %int 4
1667 %array1 = OpTypeArray %int %int_4
1668 %array2 = OpTypeArray %float %int_4
1669 %const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4
1670 %void_fn = OpTypeFunction %void
1671 %func = OpFunction %void None %void_fn
1672 %1 = OpLabel
1673 %copy = OpCopyLogical %array2 %const_array
1674 OpReturn
1675 OpFunctionEnd
1676 )";
1677 
1678   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1679   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1680   EXPECT_THAT(
1681       getDiagnosticString(),
1682       HasSubstr("Result Type does not logically match the Operand type"));
1683 }
1684 
TEST_F(ValidateComposites,CopyLogicalArrayLogicallyMatchedElement)1685 TEST_F(ValidateComposites, CopyLogicalArrayLogicallyMatchedElement) {
1686   const std::string spirv = R"(
1687 OpCapability Shader
1688 OpCapability Linkage
1689 OpMemoryModel Logical GLSL450
1690 %void = OpTypeVoid
1691 %float = OpTypeFloat 32
1692 %int = OpTypeInt 32 0
1693 %int_1 = OpConstant %int 1
1694 %inner1 = OpTypeArray %int %int_1
1695 %inner2 = OpTypeArray %int %int_1
1696 %array1 = OpTypeArray %inner1 %int_1
1697 %array2 = OpTypeArray %inner2 %int_1
1698 %const_inner = OpConstantComposite %inner1 %int_1
1699 %const_array = OpConstantComposite %array1 %const_inner
1700 %void_fn = OpTypeFunction %void
1701 %func = OpFunction %void None %void_fn
1702 %1 = OpLabel
1703 %copy = OpCopyLogical %array2 %const_array
1704 OpReturn
1705 OpFunctionEnd
1706 )";
1707 
1708   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1709   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1710 }
1711 
TEST_F(ValidateComposites,CopyLogicalStructDifferentNumberElements)1712 TEST_F(ValidateComposites, CopyLogicalStructDifferentNumberElements) {
1713   const std::string spirv = R"(
1714 OpCapability Shader
1715 OpCapability Linkage
1716 OpMemoryModel Logical GLSL450
1717 %void = OpTypeVoid
1718 %int = OpTypeInt 32 0
1719 %struct1 = OpTypeStruct
1720 %struct2 = OpTypeStruct %int
1721 %const_struct = OpConstantComposite %struct1
1722 %void_fn = OpTypeFunction %void
1723 %func = OpFunction %void None %void_fn
1724 %1 = OpLabel
1725 %copy = OpCopyLogical %struct2 %const_struct
1726 OpReturn
1727 OpFunctionEnd
1728 )";
1729 
1730   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1731   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1732   EXPECT_THAT(
1733       getDiagnosticString(),
1734       HasSubstr("Result Type does not logically match the Operand type"));
1735 }
1736 
TEST_F(ValidateComposites,CopyLogicalStructDifferentElement)1737 TEST_F(ValidateComposites, CopyLogicalStructDifferentElement) {
1738   const std::string spirv = R"(
1739 OpCapability Shader
1740 OpCapability Linkage
1741 OpMemoryModel Logical GLSL450
1742 %void = OpTypeVoid
1743 %uint = OpTypeInt 32 0
1744 %int = OpTypeInt 32 1
1745 %int_0 = OpConstant %int 0
1746 %uint_0 = OpConstant %uint 0
1747 %struct1 = OpTypeStruct %int %uint
1748 %struct2 = OpTypeStruct %int %int
1749 %const_struct = OpConstantComposite %struct1 %int_0 %uint_0
1750 %void_fn = OpTypeFunction %void
1751 %func = OpFunction %void None %void_fn
1752 %1 = OpLabel
1753 %copy = OpCopyLogical %struct2 %const_struct
1754 OpReturn
1755 OpFunctionEnd
1756 )";
1757 
1758   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1759   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1760   EXPECT_THAT(
1761       getDiagnosticString(),
1762       HasSubstr("Result Type does not logically match the Operand type"));
1763 }
1764 
TEST_F(ValidateComposites,CopyLogicalStructLogicallyMatch)1765 TEST_F(ValidateComposites, CopyLogicalStructLogicallyMatch) {
1766   const std::string spirv = R"(
1767 OpCapability Shader
1768 OpCapability Linkage
1769 OpMemoryModel Logical GLSL450
1770 %void = OpTypeVoid
1771 %int = OpTypeInt 32 0
1772 %int_1 = OpConstant %int 1
1773 %array1 = OpTypeArray %int %int_1
1774 %array2 = OpTypeArray %int %int_1
1775 %struct1 = OpTypeStruct %int %array1
1776 %struct2 = OpTypeStruct %int %array2
1777 %const_array = OpConstantComposite %array1 %int_1
1778 %const_struct = OpConstantComposite %struct1 %int_1 %const_array
1779 %void_fn = OpTypeFunction %void
1780 %func = OpFunction %void None %void_fn
1781 %1 = OpLabel
1782 %copy = OpCopyLogical %struct2 %const_struct
1783 OpReturn
1784 OpFunctionEnd
1785 )";
1786 
1787   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1788   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1789 }
1790 
1791 using ValidateSmallComposites = spvtest::ValidateBase<std::string>;
1792 
GetSmallCompositesCodeGenerator()1793 CodeGenerator GetSmallCompositesCodeGenerator() {
1794   CodeGenerator generator;
1795   generator.capabilities_ = R"(
1796 OpCapability Shader
1797 OpCapability Linkage
1798 OpCapability UniformAndStorageBuffer16BitAccess
1799 OpCapability UniformAndStorageBuffer8BitAccess
1800 )";
1801   generator.extensions_ = R"(
1802 OpExtension "SPV_KHR_16bit_storage"
1803 OpExtension "SPV_KHR_8bit_storage"
1804 )";
1805   generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
1806   generator.before_types_ = R"(
1807 OpDecorate %char_block Block
1808 OpMemberDecorate %char_block 0 Offset 0
1809 OpDecorate %short_block Block
1810 OpMemberDecorate %short_block 0 Offset 0
1811 OpDecorate %half_block Block
1812 OpMemberDecorate %half_block 0 Offset 0
1813 )";
1814   generator.types_ = R"(
1815 %void = OpTypeVoid
1816 %int = OpTypeInt 32 0
1817 %int_0 = OpConstant %int 0
1818 %int_1 = OpConstant %int 1
1819 %char = OpTypeInt 8 0
1820 %char2 = OpTypeVector %char 2
1821 %short = OpTypeInt 16 0
1822 %short2 = OpTypeVector %short 2
1823 %half = OpTypeFloat 16
1824 %half2 = OpTypeVector %half 2
1825 %char_block = OpTypeStruct %char2
1826 %short_block = OpTypeStruct %short2
1827 %half_block = OpTypeStruct %half2
1828 %ptr_ssbo_char_block = OpTypePointer StorageBuffer %char_block
1829 %ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2
1830 %ptr_ssbo_char = OpTypePointer StorageBuffer %char
1831 %ptr_ssbo_short_block = OpTypePointer StorageBuffer %short_block
1832 %ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2
1833 %ptr_ssbo_short = OpTypePointer StorageBuffer %short
1834 %ptr_ssbo_half_block = OpTypePointer StorageBuffer %half_block
1835 %ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2
1836 %ptr_ssbo_half = OpTypePointer StorageBuffer %half
1837 %void_fn = OpTypeFunction %void
1838 %char_var = OpVariable %ptr_ssbo_char_block StorageBuffer
1839 %short_var = OpVariable %ptr_ssbo_short_block StorageBuffer
1840 %half_var = OpVariable %ptr_ssbo_half_block StorageBuffer
1841 )";
1842   generator.after_types_ = R"(
1843 %func = OpFunction %void None %void_fn
1844 %entry = OpLabel
1845 %char2_gep = OpAccessChain %ptr_ssbo_char2 %char_var %int_0
1846 %ld_char2 = OpLoad %char2 %char2_gep
1847 %char_gep = OpAccessChain %ptr_ssbo_char %char_var %int_0 %int_0
1848 %ld_char = OpLoad %char %char_gep
1849 %short2_gep = OpAccessChain %ptr_ssbo_short2 %short_var %int_0
1850 %ld_short2 = OpLoad %short2 %short2_gep
1851 %short_gep = OpAccessChain %ptr_ssbo_short %short_var %int_0 %int_0
1852 %ld_short = OpLoad %short %short_gep
1853 %half2_gep = OpAccessChain %ptr_ssbo_half2 %half_var %int_0
1854 %ld_half2 = OpLoad %half2 %half2_gep
1855 %half_gep = OpAccessChain %ptr_ssbo_half %half_var %int_0 %int_0
1856 %ld_half = OpLoad %half %half_gep
1857 )";
1858   generator.add_at_the_end_ = R"(
1859 OpReturn
1860 OpFunctionEnd
1861 )";
1862   return generator;
1863 }
1864 
TEST_P(ValidateSmallComposites,VectorExtractDynamic)1865 TEST_P(ValidateSmallComposites, VectorExtractDynamic) {
1866   std::string type = GetParam();
1867   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1868   std::string inst =
1869       "%inst = OpVectorExtractDynamic %" + type + " %ld_" + type + "2 %int_0\n";
1870   generator.after_types_ += inst;
1871   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1872   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1873             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1874   EXPECT_THAT(getDiagnosticString(),
1875               HasSubstr("Cannot extract from a vector of 8- or 16-bit types"));
1876 }
1877 
TEST_P(ValidateSmallComposites,VectorInsertDynamic)1878 TEST_P(ValidateSmallComposites, VectorInsertDynamic) {
1879   std::string type = GetParam();
1880   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1881   std::string inst = "%inst = OpVectorInsertDynamic %" + type + "2 %ld_" +
1882                      type + "2 %ld_" + type + " %int_0\n";
1883   generator.after_types_ += inst;
1884   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1885   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1886             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1887   EXPECT_THAT(getDiagnosticString(),
1888               HasSubstr("Cannot insert into a vector of 8- or 16-bit types"));
1889 }
1890 
TEST_P(ValidateSmallComposites,VectorShuffle)1891 TEST_P(ValidateSmallComposites, VectorShuffle) {
1892   std::string type = GetParam();
1893   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1894   std::string inst = "%inst = OpVectorShuffle %" + type + "2 %ld_" + type +
1895                      "2 %ld_" + type + "2 0 0\n";
1896   generator.after_types_ += inst;
1897   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1898   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1899             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1900   EXPECT_THAT(getDiagnosticString(),
1901               HasSubstr("Cannot shuffle a vector of 8- or 16-bit types"));
1902 }
1903 
TEST_P(ValidateSmallComposites,CompositeConstruct)1904 TEST_P(ValidateSmallComposites, CompositeConstruct) {
1905   std::string type = GetParam();
1906   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1907   std::string inst = "%inst = OpCompositeConstruct %" + type + "2 %ld_" + type +
1908                      " %ld_" + type + "\n";
1909   generator.after_types_ += inst;
1910   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1911   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1912             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1913   EXPECT_THAT(
1914       getDiagnosticString(),
1915       HasSubstr("Cannot create a composite containing 8- or 16-bit types"));
1916 }
1917 
TEST_P(ValidateSmallComposites,CompositeExtract)1918 TEST_P(ValidateSmallComposites, CompositeExtract) {
1919   std::string type = GetParam();
1920   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1921   std::string inst =
1922       "%inst = OpCompositeExtract %" + type + " %ld_" + type + "2 0\n";
1923   generator.after_types_ += inst;
1924   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1925   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1926             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1927   EXPECT_THAT(
1928       getDiagnosticString(),
1929       HasSubstr("Cannot extract from a composite of 8- or 16-bit types"));
1930 }
1931 
TEST_P(ValidateSmallComposites,CompositeInsert)1932 TEST_P(ValidateSmallComposites, CompositeInsert) {
1933   std::string type = GetParam();
1934   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1935   std::string inst = "%inst = OpCompositeInsert %" + type + "2 %ld_" + type +
1936                      " %ld_" + type + "2 0\n";
1937   generator.after_types_ += inst;
1938   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1939   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1940             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1941   EXPECT_THAT(
1942       getDiagnosticString(),
1943       HasSubstr("Cannot insert into a composite of 8- or 16-bit types"));
1944 }
1945 
TEST_P(ValidateSmallComposites,CopyObject)1946 TEST_P(ValidateSmallComposites, CopyObject) {
1947   std::string type = GetParam();
1948   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1949   std::string inst = "%inst = OpCopyObject %" + type + "2 %ld_" + type + "2\n";
1950   generator.after_types_ += inst;
1951   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1952   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1953 }
1954 
1955 INSTANTIATE_TEST_SUITE_P(SmallCompositeInstructions, ValidateSmallComposites,
1956                          Values("char", "short", "half"));
1957 
TEST_F(ValidateComposites,HalfMatrixCannotTranspose)1958 TEST_F(ValidateComposites, HalfMatrixCannotTranspose) {
1959   const std::string spirv = R"(
1960 OpCapability Shader
1961 OpCapability Linkage
1962 OpCapability UniformAndStorageBuffer16BitAccess
1963 OpExtension "SPV_KHR_16bit_storage"
1964 OpMemoryModel Logical GLSL450
1965 OpDecorate %block Block
1966 OpMemberDecorate %block 0 Offset 0
1967 OpMemberDecorate %block 0 RowMajor
1968 OpMemberDecorate %block 0 MatrixStride 8
1969 %void = OpTypeVoid
1970 %int = OpTypeInt 32 0
1971 %int_0 = OpConstant %int 0
1972 %float = OpTypeFloat 16
1973 %float2 = OpTypeVector %float 2
1974 %mat2x2 = OpTypeMatrix %float2 2
1975 %block = OpTypeStruct %mat2x2
1976 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
1977 %ptr_ssbo_mat2x2 = OpTypePointer StorageBuffer %mat2x2
1978 %var = OpVariable %ptr_ssbo_block StorageBuffer
1979 %void_fn = OpTypeFunction %void
1980 %func = OpFunction %void None %void_fn
1981 %entry = OpLabel
1982 %gep = OpAccessChain %ptr_ssbo_mat2x2 %var %int_0
1983 %ld = OpLoad %mat2x2 %gep
1984 %inst = OpTranspose %mat2x2 %ld
1985 OpReturn
1986 OpFunctionEnd
1987 )";
1988 
1989   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1990   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1991             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1992   EXPECT_THAT(getDiagnosticString(),
1993               HasSubstr("Cannot transpose matrices of 16-bit floats"));
1994 }
1995 
TEST_F(ValidateComposites,CopyObjectVoid)1996 TEST_F(ValidateComposites, CopyObjectVoid) {
1997   const std::string spirv = R"(
1998                OpCapability Shader
1999           %1 = OpExtInstImport "GLSL.std.450"
2000                OpMemoryModel Logical GLSL450
2001                OpEntryPoint Fragment %4 "main"
2002                OpExecutionMode %4 OriginUpperLeft
2003                OpSource ESSL 320
2004                OpName %4 "main"
2005                OpName %6 "foo("
2006           %2 = OpTypeVoid
2007           %3 = OpTypeFunction %2
2008           %4 = OpFunction %2 None %3
2009           %5 = OpLabel
2010           %8 = OpFunctionCall %2 %6
2011          %20 = OpCopyObject %2 %8
2012                OpReturn
2013                OpFunctionEnd
2014           %6 = OpFunction %2 None %3
2015           %7 = OpLabel
2016                OpReturn
2017                OpFunctionEnd
2018 )";
2019 
2020   CompileSuccessfully(spirv);
2021   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2022   EXPECT_THAT(getDiagnosticString(),
2023               HasSubstr("OpCopyObject cannot have void result type"));
2024 }
2025 
2026 }  // namespace
2027 }  // namespace val
2028 }  // namespace spvtools
2029