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