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 %f32vec2rarr = OpTypeRuntimeArray %f32vec2
90 
91 %f32u32struct = OpTypeStruct %f32 %u32
92 %big_struct = OpTypeStruct %f32 %f32vec4 %f32mat23 %f32vec2arr3 %f32vec2rarr %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 ;   RunTimeArray arr;
154 ; }
155 
156 %f32arr = OpTypeRuntimeArray %float
157 %v4float = OpTypeVector %float 4
158 %array5_mat4x3 = OpTypeArray %mat4x3 %int_5
159 %array5_vec4 = OpTypeArray %v4float %int_5
160 %_ptr_Uniform_float = OpTypePointer Uniform %float
161 %_ptr_Function_vec4 = OpTypePointer Function %v4float
162 %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float
163 %struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3
164 %struct_blockName = OpTypeStruct %struct_s %int %f32arr
165 %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName
166 %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s
167 %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3
168 %_ptr_Uniform_mat4x3 = OpTypePointer Uniform %mat4x3
169 %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
170 %blockName_var = OpVariable %_ptr_Uniform_blockName Uniform
171 %spec_int = OpSpecConstant %int 2
172 %func = OpFunction %void None %void_f
173 %my_label = OpLabel
174 )";
175 }
176 
TEST_F(ValidateComposites,VectorExtractDynamicSuccess)177 TEST_F(ValidateComposites, VectorExtractDynamicSuccess) {
178   const std::string body = R"(
179 %val1 = OpVectorExtractDynamic %f32 %f32vec4_0123 %u32_0
180 )";
181 
182   CompileSuccessfully(GenerateShaderCode(body).c_str());
183   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
184 }
185 
TEST_F(ValidateComposites,VectorExtractDynamicWrongResultType)186 TEST_F(ValidateComposites, VectorExtractDynamicWrongResultType) {
187   const std::string body = R"(
188 %val1 = OpVectorExtractDynamic %f32vec4 %f32vec4_0123 %u32_0
189 )";
190 
191   CompileSuccessfully(GenerateShaderCode(body).c_str());
192   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
193   EXPECT_THAT(getDiagnosticString(),
194               HasSubstr("Expected Result Type to be a scalar type"));
195 }
196 
TEST_F(ValidateComposites,VectorExtractDynamicNotVector)197 TEST_F(ValidateComposites, VectorExtractDynamicNotVector) {
198   const std::string body = R"(
199 %val1 = OpVectorExtractDynamic %f32 %f32mat22_1212 %u32_0
200 )";
201 
202   CompileSuccessfully(GenerateShaderCode(body).c_str());
203   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
204   EXPECT_THAT(getDiagnosticString(),
205               HasSubstr("Expected Vector type to be OpTypeVector"));
206 }
207 
TEST_F(ValidateComposites,VectorExtractDynamicWrongVectorComponent)208 TEST_F(ValidateComposites, VectorExtractDynamicWrongVectorComponent) {
209   const std::string body = R"(
210 %val1 = OpVectorExtractDynamic %f32 %u32vec4_0123 %u32_0
211 )";
212 
213   CompileSuccessfully(GenerateShaderCode(body).c_str());
214   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
215   EXPECT_THAT(
216       getDiagnosticString(),
217       HasSubstr("Expected Vector component type to be equal to Result Type"));
218 }
219 
TEST_F(ValidateComposites,VectorExtractDynamicWrongIndexType)220 TEST_F(ValidateComposites, VectorExtractDynamicWrongIndexType) {
221   const std::string body = R"(
222 %val1 = OpVectorExtractDynamic %f32 %f32vec4_0123 %f32_0
223 )";
224 
225   CompileSuccessfully(GenerateShaderCode(body).c_str());
226   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
227   EXPECT_THAT(getDiagnosticString(),
228               HasSubstr("Expected Index to be int scalar"));
229 }
230 
TEST_F(ValidateComposites,VectorInsertDynamicSuccess)231 TEST_F(ValidateComposites, VectorInsertDynamicSuccess) {
232   const std::string body = R"(
233 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %f32_1 %u32_0
234 )";
235 
236   CompileSuccessfully(GenerateShaderCode(body).c_str());
237   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
238 }
239 
TEST_F(ValidateComposites,VectorInsertDynamicWrongResultType)240 TEST_F(ValidateComposites, VectorInsertDynamicWrongResultType) {
241   const std::string body = R"(
242 %val1 = OpVectorInsertDynamic %f32 %f32vec4_0123 %f32_1 %u32_0
243 )";
244 
245   CompileSuccessfully(GenerateShaderCode(body).c_str());
246   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
247   EXPECT_THAT(getDiagnosticString(),
248               HasSubstr("Expected Result Type to be OpTypeVector"));
249 }
250 
TEST_F(ValidateComposites,VectorInsertDynamicNotVector)251 TEST_F(ValidateComposites, VectorInsertDynamicNotVector) {
252   const std::string body = R"(
253 %val1 = OpVectorInsertDynamic %f32vec4 %f32mat22_1212 %f32_1 %u32_0
254 )";
255 
256   CompileSuccessfully(GenerateShaderCode(body).c_str());
257   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
258   EXPECT_THAT(getDiagnosticString(),
259               HasSubstr("Expected Vector type to be equal to Result Type"));
260 }
261 
TEST_F(ValidateComposites,VectorInsertDynamicWrongComponentType)262 TEST_F(ValidateComposites, VectorInsertDynamicWrongComponentType) {
263   const std::string body = R"(
264 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %u32_1 %u32_0
265 )";
266 
267   CompileSuccessfully(GenerateShaderCode(body).c_str());
268   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
269   EXPECT_THAT(getDiagnosticString(),
270               HasSubstr("Expected Component type to be equal to Result Type "
271                         "component type"));
272 }
273 
TEST_F(ValidateComposites,VectorInsertDynamicWrongIndexType)274 TEST_F(ValidateComposites, VectorInsertDynamicWrongIndexType) {
275   const std::string body = R"(
276 %val1 = OpVectorInsertDynamic %f32vec4 %f32vec4_0123 %f32_1 %f32_0
277 )";
278 
279   CompileSuccessfully(GenerateShaderCode(body).c_str());
280   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
281   EXPECT_THAT(getDiagnosticString(),
282               HasSubstr("Expected Index to be int scalar"));
283 }
284 
TEST_F(ValidateComposites,CompositeConstructNotComposite)285 TEST_F(ValidateComposites, CompositeConstructNotComposite) {
286   const std::string body = R"(
287 %val1 = OpCompositeConstruct %f32 %f32_1
288 )";
289 
290   CompileSuccessfully(GenerateShaderCode(body).c_str());
291   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
292   EXPECT_THAT(getDiagnosticString(),
293               HasSubstr("Expected Result Type to be a composite type"));
294 }
295 
TEST_F(ValidateComposites,CompositeConstructVectorSuccess)296 TEST_F(ValidateComposites, CompositeConstructVectorSuccess) {
297   const std::string body = R"(
298 %val1 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32vec2_12
299 %val2 = OpCompositeConstruct %f32vec4 %f32vec2_12 %f32_0 %f32_0
300 %val3 = OpCompositeConstruct %f32vec4 %f32_0 %f32_0 %f32vec2_12
301 %val4 = OpCompositeConstruct %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3
302 )";
303 
304   CompileSuccessfully(GenerateShaderCode(body).c_str());
305   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
306 }
307 
TEST_F(ValidateComposites,CompositeConstructVectorOnlyOneConstituent)308 TEST_F(ValidateComposites, CompositeConstructVectorOnlyOneConstituent) {
309   const std::string body = R"(
310 %val1 = OpCompositeConstruct %f32vec4 %f32vec4_0123
311 )";
312 
313   CompileSuccessfully(GenerateShaderCode(body).c_str());
314   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
315   EXPECT_THAT(getDiagnosticString(),
316               HasSubstr("Expected number of constituents to be at least 2"));
317 }
318 
TEST_F(ValidateComposites,CompositeConstructVectorWrongConsituent1)319 TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent1) {
320   const std::string body = R"(
321 %val1 = OpCompositeConstruct %f32vec4 %f32 %f32vec2_12
322 )";
323 
324   CompileSuccessfully(GenerateShaderCode(body).c_str());
325   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
326   EXPECT_THAT(getDiagnosticString(), 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 100
648 %val16 = OpCompositeExtract %f32 %struct 4 1000 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 100
872 %val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 1000 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 3 members. "
1386                         "Largest valid index is 2."));
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 3 members. Largest valid index "
1407                 "is 2."));
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 =
1490       R"(
1491 OpCapability Shader
1492 OpCapability Float16
1493 OpCapability CooperativeMatrixNV
1494 OpExtension "SPV_NV_cooperative_matrix"
1495 OpMemoryModel Logical GLSL450
1496 OpEntryPoint GLCompute %main "main"
1497 %void = OpTypeVoid
1498 %func = OpTypeFunction %void
1499 %bool = OpTypeBool
1500 %f16 = OpTypeFloat 16
1501 %f32 = OpTypeFloat 32
1502 %u32 = OpTypeInt 32 0
1503 
1504 %u32_8 = OpConstant %u32 8
1505 %subgroup = OpConstant %u32 3
1506 
1507 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1508 
1509 %f32_1 = OpConstant %f32 1
1510 
1511 %f16mat_1 = OpConstantComposite %f16mat %f32_1
1512 
1513 %main = OpFunction %void None %func
1514 %main_entry = OpLabel
1515 
1516 OpReturn
1517 OpFunctionEnd)";
1518 
1519   CompileSuccessfully(body.c_str());
1520   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1521   EXPECT_THAT(
1522       getDiagnosticString(),
1523       HasSubstr("OpConstantComposite Constituent <id> '11[%float_1]' type does "
1524                 "not match the Result Type <id> '10[%10]'s component type."));
1525 }
1526 
TEST_F(ValidateComposites,CoopMatCompositeConstructMismatchFail)1527 TEST_F(ValidateComposites, CoopMatCompositeConstructMismatchFail) {
1528   const std::string body =
1529       R"(
1530 OpCapability Shader
1531 OpCapability Float16
1532 OpCapability CooperativeMatrixNV
1533 OpExtension "SPV_NV_cooperative_matrix"
1534 OpMemoryModel Logical GLSL450
1535 OpEntryPoint GLCompute %main "main"
1536 %void = OpTypeVoid
1537 %func = OpTypeFunction %void
1538 %bool = OpTypeBool
1539 %f16 = OpTypeFloat 16
1540 %f32 = OpTypeFloat 32
1541 %u32 = OpTypeInt 32 0
1542 
1543 %u32_8 = OpConstant %u32 8
1544 %subgroup = OpConstant %u32 3
1545 
1546 %f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8
1547 
1548 %f32_1 = OpConstant %f32 1
1549 
1550 %main = OpFunction %void None %func
1551 %main_entry = OpLabel
1552 
1553 %f16mat_1 = OpCompositeConstruct %f16mat %f32_1
1554 
1555 OpReturn
1556 OpFunctionEnd)";
1557 
1558   CompileSuccessfully(body.c_str());
1559   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1560   EXPECT_THAT(
1561       getDiagnosticString(),
1562       HasSubstr("Expected Constituent type to be equal to the component type"));
1563 }
1564 
TEST_F(ValidateComposites,ExtractDynamicLabelIndex)1565 TEST_F(ValidateComposites, ExtractDynamicLabelIndex) {
1566   const std::string spirv = R"(
1567 OpCapability Shader
1568 OpCapability Linkage
1569 OpMemoryModel Logical GLSL450
1570 %void = OpTypeVoid
1571 %float = OpTypeFloat 32
1572 %v4float = OpTypeVector %float 4
1573 %void_fn = OpTypeFunction %void
1574 %float_0 = OpConstant %float 0
1575 %v4float_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
1576 %func = OpFunction %void None %void_fn
1577 %1 = OpLabel
1578 %ex = OpVectorExtractDynamic %float %v4float_0 %v4float_0
1579 OpReturn
1580 OpFunctionEnd
1581 )";
1582 
1583   CompileSuccessfully(spirv);
1584   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1585   EXPECT_THAT(getDiagnosticString(),
1586               HasSubstr("Expected Index to be int scalar"));
1587 }
1588 
TEST_F(ValidateComposites,CopyLogicalSameType)1589 TEST_F(ValidateComposites, CopyLogicalSameType) {
1590   const std::string spirv = R"(
1591 OpCapability Shader
1592 OpCapability Linkage
1593 OpMemoryModel Logical GLSL450
1594 %void = OpTypeVoid
1595 %struct = OpTypeStruct
1596 %const_struct = OpConstantComposite %struct
1597 %void_fn = OpTypeFunction %void
1598 %func = OpFunction %void None %void_fn
1599 %1 = OpLabel
1600 %copy = OpCopyLogical %struct %const_struct
1601 OpReturn
1602 OpFunctionEnd
1603 )";
1604 
1605   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1606   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1607   EXPECT_THAT(getDiagnosticString(),
1608               HasSubstr("Result Type must not equal the Operand type"));
1609 }
1610 
TEST_F(ValidateComposites,CopyLogicalSameStructDifferentId)1611 TEST_F(ValidateComposites, CopyLogicalSameStructDifferentId) {
1612   const std::string spirv = R"(
1613 OpCapability Shader
1614 OpCapability Linkage
1615 OpMemoryModel Logical GLSL450
1616 %void = OpTypeVoid
1617 %struct1 = OpTypeStruct
1618 %struct2 = OpTypeStruct
1619 %const_struct = OpConstantComposite %struct1
1620 %void_fn = OpTypeFunction %void
1621 %func = OpFunction %void None %void_fn
1622 %1 = OpLabel
1623 %copy = OpCopyLogical %struct2 %const_struct
1624 OpReturn
1625 OpFunctionEnd
1626 )";
1627 
1628   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1629   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1630 }
1631 
TEST_F(ValidateComposites,CopyLogicalArrayDifferentLength)1632 TEST_F(ValidateComposites, CopyLogicalArrayDifferentLength) {
1633   const std::string spirv = R"(
1634 OpCapability Shader
1635 OpCapability Linkage
1636 OpMemoryModel Logical GLSL450
1637 %void = OpTypeVoid
1638 %int = OpTypeInt 32 0
1639 %int_4 = OpConstant %int 4
1640 %int_5 = OpConstant %int 5
1641 %array1 = OpTypeArray %int %int_4
1642 %array2 = OpTypeArray %int %int_5
1643 %const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4
1644 %void_fn = OpTypeFunction %void
1645 %func = OpFunction %void None %void_fn
1646 %1 = OpLabel
1647 %copy = OpCopyLogical %array2 %const_array
1648 OpReturn
1649 OpFunctionEnd
1650 )";
1651 
1652   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1653   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1654   EXPECT_THAT(
1655       getDiagnosticString(),
1656       HasSubstr("Result Type does not logically match the Operand type"));
1657 }
1658 
TEST_F(ValidateComposites,CopyLogicalArrayDifferentElement)1659 TEST_F(ValidateComposites, CopyLogicalArrayDifferentElement) {
1660   const std::string spirv = R"(
1661 OpCapability Shader
1662 OpCapability Linkage
1663 OpMemoryModel Logical GLSL450
1664 %void = OpTypeVoid
1665 %float = OpTypeFloat 32
1666 %int = OpTypeInt 32 0
1667 %int_4 = OpConstant %int 4
1668 %array1 = OpTypeArray %int %int_4
1669 %array2 = OpTypeArray %float %int_4
1670 %const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4
1671 %void_fn = OpTypeFunction %void
1672 %func = OpFunction %void None %void_fn
1673 %1 = OpLabel
1674 %copy = OpCopyLogical %array2 %const_array
1675 OpReturn
1676 OpFunctionEnd
1677 )";
1678 
1679   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1680   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1681   EXPECT_THAT(
1682       getDiagnosticString(),
1683       HasSubstr("Result Type does not logically match the Operand type"));
1684 }
1685 
TEST_F(ValidateComposites,CopyLogicalArrayLogicallyMatchedElement)1686 TEST_F(ValidateComposites, CopyLogicalArrayLogicallyMatchedElement) {
1687   const std::string spirv = R"(
1688 OpCapability Shader
1689 OpCapability Linkage
1690 OpMemoryModel Logical GLSL450
1691 %void = OpTypeVoid
1692 %float = OpTypeFloat 32
1693 %int = OpTypeInt 32 0
1694 %int_1 = OpConstant %int 1
1695 %inner1 = OpTypeArray %int %int_1
1696 %inner2 = OpTypeArray %int %int_1
1697 %array1 = OpTypeArray %inner1 %int_1
1698 %array2 = OpTypeArray %inner2 %int_1
1699 %const_inner = OpConstantComposite %inner1 %int_1
1700 %const_array = OpConstantComposite %array1 %const_inner
1701 %void_fn = OpTypeFunction %void
1702 %func = OpFunction %void None %void_fn
1703 %1 = OpLabel
1704 %copy = OpCopyLogical %array2 %const_array
1705 OpReturn
1706 OpFunctionEnd
1707 )";
1708 
1709   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1710   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1711 }
1712 
TEST_F(ValidateComposites,CopyLogicalStructDifferentNumberElements)1713 TEST_F(ValidateComposites, CopyLogicalStructDifferentNumberElements) {
1714   const std::string spirv = R"(
1715 OpCapability Shader
1716 OpCapability Linkage
1717 OpMemoryModel Logical GLSL450
1718 %void = OpTypeVoid
1719 %int = OpTypeInt 32 0
1720 %struct1 = OpTypeStruct
1721 %struct2 = OpTypeStruct %int
1722 %const_struct = OpConstantComposite %struct1
1723 %void_fn = OpTypeFunction %void
1724 %func = OpFunction %void None %void_fn
1725 %1 = OpLabel
1726 %copy = OpCopyLogical %struct2 %const_struct
1727 OpReturn
1728 OpFunctionEnd
1729 )";
1730 
1731   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1732   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1733   EXPECT_THAT(
1734       getDiagnosticString(),
1735       HasSubstr("Result Type does not logically match the Operand type"));
1736 }
1737 
TEST_F(ValidateComposites,CopyLogicalStructDifferentElement)1738 TEST_F(ValidateComposites, CopyLogicalStructDifferentElement) {
1739   const std::string spirv = R"(
1740 OpCapability Shader
1741 OpCapability Linkage
1742 OpMemoryModel Logical GLSL450
1743 %void = OpTypeVoid
1744 %uint = OpTypeInt 32 0
1745 %int = OpTypeInt 32 1
1746 %int_0 = OpConstant %int 0
1747 %uint_0 = OpConstant %uint 0
1748 %struct1 = OpTypeStruct %int %uint
1749 %struct2 = OpTypeStruct %int %int
1750 %const_struct = OpConstantComposite %struct1 %int_0 %uint_0
1751 %void_fn = OpTypeFunction %void
1752 %func = OpFunction %void None %void_fn
1753 %1 = OpLabel
1754 %copy = OpCopyLogical %struct2 %const_struct
1755 OpReturn
1756 OpFunctionEnd
1757 )";
1758 
1759   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1760   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1761   EXPECT_THAT(
1762       getDiagnosticString(),
1763       HasSubstr("Result Type does not logically match the Operand type"));
1764 }
1765 
TEST_F(ValidateComposites,CopyLogicalStructLogicallyMatch)1766 TEST_F(ValidateComposites, CopyLogicalStructLogicallyMatch) {
1767   const std::string spirv = R"(
1768 OpCapability Shader
1769 OpCapability Linkage
1770 OpMemoryModel Logical GLSL450
1771 %void = OpTypeVoid
1772 %int = OpTypeInt 32 0
1773 %int_1 = OpConstant %int 1
1774 %array1 = OpTypeArray %int %int_1
1775 %array2 = OpTypeArray %int %int_1
1776 %struct1 = OpTypeStruct %int %array1
1777 %struct2 = OpTypeStruct %int %array2
1778 %const_array = OpConstantComposite %array1 %int_1
1779 %const_struct = OpConstantComposite %struct1 %int_1 %const_array
1780 %void_fn = OpTypeFunction %void
1781 %func = OpFunction %void None %void_fn
1782 %1 = OpLabel
1783 %copy = OpCopyLogical %struct2 %const_struct
1784 OpReturn
1785 OpFunctionEnd
1786 )";
1787 
1788   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4);
1789   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4));
1790 }
1791 
1792 using ValidateSmallComposites = spvtest::ValidateBase<std::string>;
1793 
GetSmallCompositesCodeGenerator()1794 CodeGenerator GetSmallCompositesCodeGenerator() {
1795   CodeGenerator generator;
1796   generator.capabilities_ = R"(
1797 OpCapability Shader
1798 OpCapability Linkage
1799 OpCapability UniformAndStorageBuffer16BitAccess
1800 OpCapability UniformAndStorageBuffer8BitAccess
1801 )";
1802   generator.extensions_ = R"(
1803 OpExtension "SPV_KHR_16bit_storage"
1804 OpExtension "SPV_KHR_8bit_storage"
1805 )";
1806   generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
1807   generator.before_types_ = R"(
1808 OpDecorate %char_block Block
1809 OpMemberDecorate %char_block 0 Offset 0
1810 OpDecorate %short_block Block
1811 OpMemberDecorate %short_block 0 Offset 0
1812 OpDecorate %half_block Block
1813 OpMemberDecorate %half_block 0 Offset 0
1814 )";
1815   generator.types_ = R"(
1816 %void = OpTypeVoid
1817 %int = OpTypeInt 32 0
1818 %int_0 = OpConstant %int 0
1819 %int_1 = OpConstant %int 1
1820 %char = OpTypeInt 8 0
1821 %char2 = OpTypeVector %char 2
1822 %short = OpTypeInt 16 0
1823 %short2 = OpTypeVector %short 2
1824 %half = OpTypeFloat 16
1825 %half2 = OpTypeVector %half 2
1826 %char_block = OpTypeStruct %char2
1827 %short_block = OpTypeStruct %short2
1828 %half_block = OpTypeStruct %half2
1829 %ptr_ssbo_char_block = OpTypePointer StorageBuffer %char_block
1830 %ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2
1831 %ptr_ssbo_char = OpTypePointer StorageBuffer %char
1832 %ptr_ssbo_short_block = OpTypePointer StorageBuffer %short_block
1833 %ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2
1834 %ptr_ssbo_short = OpTypePointer StorageBuffer %short
1835 %ptr_ssbo_half_block = OpTypePointer StorageBuffer %half_block
1836 %ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2
1837 %ptr_ssbo_half = OpTypePointer StorageBuffer %half
1838 %void_fn = OpTypeFunction %void
1839 %char_var = OpVariable %ptr_ssbo_char_block StorageBuffer
1840 %short_var = OpVariable %ptr_ssbo_short_block StorageBuffer
1841 %half_var = OpVariable %ptr_ssbo_half_block StorageBuffer
1842 )";
1843   generator.after_types_ = R"(
1844 %func = OpFunction %void None %void_fn
1845 %entry = OpLabel
1846 %char2_gep = OpAccessChain %ptr_ssbo_char2 %char_var %int_0
1847 %ld_char2 = OpLoad %char2 %char2_gep
1848 %char_gep = OpAccessChain %ptr_ssbo_char %char_var %int_0 %int_0
1849 %ld_char = OpLoad %char %char_gep
1850 %short2_gep = OpAccessChain %ptr_ssbo_short2 %short_var %int_0
1851 %ld_short2 = OpLoad %short2 %short2_gep
1852 %short_gep = OpAccessChain %ptr_ssbo_short %short_var %int_0 %int_0
1853 %ld_short = OpLoad %short %short_gep
1854 %half2_gep = OpAccessChain %ptr_ssbo_half2 %half_var %int_0
1855 %ld_half2 = OpLoad %half2 %half2_gep
1856 %half_gep = OpAccessChain %ptr_ssbo_half %half_var %int_0 %int_0
1857 %ld_half = OpLoad %half %half_gep
1858 )";
1859   generator.add_at_the_end_ = R"(
1860 OpReturn
1861 OpFunctionEnd
1862 )";
1863   return generator;
1864 }
1865 
TEST_P(ValidateSmallComposites,VectorExtractDynamic)1866 TEST_P(ValidateSmallComposites, VectorExtractDynamic) {
1867   std::string type = GetParam();
1868   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1869   std::string inst =
1870       "%inst = OpVectorExtractDynamic %" + type + " %ld_" + type + "2 %int_0\n";
1871   generator.after_types_ += inst;
1872   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1873   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1874             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1875   EXPECT_THAT(getDiagnosticString(),
1876               HasSubstr("Cannot extract from a vector of 8- or 16-bit types"));
1877 }
1878 
TEST_P(ValidateSmallComposites,VectorInsertDynamic)1879 TEST_P(ValidateSmallComposites, VectorInsertDynamic) {
1880   std::string type = GetParam();
1881   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1882   std::string inst = "%inst = OpVectorInsertDynamic %" + type + "2 %ld_" +
1883                      type + "2 %ld_" + type + " %int_0\n";
1884   generator.after_types_ += inst;
1885   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1886   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1887             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1888   EXPECT_THAT(getDiagnosticString(),
1889               HasSubstr("Cannot insert into a vector of 8- or 16-bit types"));
1890 }
1891 
TEST_P(ValidateSmallComposites,VectorShuffle)1892 TEST_P(ValidateSmallComposites, VectorShuffle) {
1893   std::string type = GetParam();
1894   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1895   std::string inst = "%inst = OpVectorShuffle %" + type + "2 %ld_" + type +
1896                      "2 %ld_" + type + "2 0 0\n";
1897   generator.after_types_ += inst;
1898   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1899   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1900             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1901   EXPECT_THAT(getDiagnosticString(),
1902               HasSubstr("Cannot shuffle a vector of 8- or 16-bit types"));
1903 }
1904 
TEST_P(ValidateSmallComposites,CompositeConstruct)1905 TEST_P(ValidateSmallComposites, CompositeConstruct) {
1906   std::string type = GetParam();
1907   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1908   std::string inst = "%inst = OpCompositeConstruct %" + type + "2 %ld_" + type +
1909                      " %ld_" + type + "\n";
1910   generator.after_types_ += inst;
1911   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1912   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1913             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1914   EXPECT_THAT(
1915       getDiagnosticString(),
1916       HasSubstr("Cannot create a composite containing 8- or 16-bit types"));
1917 }
1918 
TEST_P(ValidateSmallComposites,CompositeExtract)1919 TEST_P(ValidateSmallComposites, CompositeExtract) {
1920   std::string type = GetParam();
1921   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1922   std::string inst =
1923       "%inst = OpCompositeExtract %" + type + " %ld_" + type + "2 0\n";
1924   generator.after_types_ += inst;
1925   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1926   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1927             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1928   EXPECT_THAT(
1929       getDiagnosticString(),
1930       HasSubstr("Cannot extract from a composite of 8- or 16-bit types"));
1931 }
1932 
TEST_P(ValidateSmallComposites,CompositeInsert)1933 TEST_P(ValidateSmallComposites, CompositeInsert) {
1934   std::string type = GetParam();
1935   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1936   std::string inst = "%inst = OpCompositeInsert %" + type + "2 %ld_" + type +
1937                      " %ld_" + type + "2 0\n";
1938   generator.after_types_ += inst;
1939   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1940   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1941             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1942   EXPECT_THAT(
1943       getDiagnosticString(),
1944       HasSubstr("Cannot insert into a composite of 8- or 16-bit types"));
1945 }
1946 
TEST_P(ValidateSmallComposites,CopyObject)1947 TEST_P(ValidateSmallComposites, CopyObject) {
1948   std::string type = GetParam();
1949   CodeGenerator generator = GetSmallCompositesCodeGenerator();
1950   std::string inst = "%inst = OpCopyObject %" + type + "2 %ld_" + type + "2\n";
1951   generator.after_types_ += inst;
1952   CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3);
1953   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1954 }
1955 
1956 INSTANTIATE_TEST_SUITE_P(SmallCompositeInstructions, ValidateSmallComposites,
1957                          Values("char", "short", "half"));
1958 
TEST_F(ValidateComposites,HalfMatrixCannotTranspose)1959 TEST_F(ValidateComposites, HalfMatrixCannotTranspose) {
1960   const std::string spirv = R"(
1961 OpCapability Shader
1962 OpCapability Linkage
1963 OpCapability UniformAndStorageBuffer16BitAccess
1964 OpExtension "SPV_KHR_16bit_storage"
1965 OpMemoryModel Logical GLSL450
1966 OpDecorate %block Block
1967 OpMemberDecorate %block 0 Offset 0
1968 OpMemberDecorate %block 0 RowMajor
1969 OpMemberDecorate %block 0 MatrixStride 8
1970 %void = OpTypeVoid
1971 %int = OpTypeInt 32 0
1972 %int_0 = OpConstant %int 0
1973 %float = OpTypeFloat 16
1974 %float2 = OpTypeVector %float 2
1975 %mat2x2 = OpTypeMatrix %float2 2
1976 %block = OpTypeStruct %mat2x2
1977 %ptr_ssbo_block = OpTypePointer StorageBuffer %block
1978 %ptr_ssbo_mat2x2 = OpTypePointer StorageBuffer %mat2x2
1979 %var = OpVariable %ptr_ssbo_block StorageBuffer
1980 %void_fn = OpTypeFunction %void
1981 %func = OpFunction %void None %void_fn
1982 %entry = OpLabel
1983 %gep = OpAccessChain %ptr_ssbo_mat2x2 %var %int_0
1984 %ld = OpLoad %mat2x2 %gep
1985 %inst = OpTranspose %mat2x2 %ld
1986 OpReturn
1987 OpFunctionEnd
1988 )";
1989 
1990   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1991   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1992             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1993   EXPECT_THAT(getDiagnosticString(),
1994               HasSubstr("Cannot transpose matrices of 16-bit floats"));
1995 }
1996 
1997 }  // namespace
1998 }  // namespace val
1999 }  // namespace spvtools
2000