• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 The Khronos Group 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 #include <vector>
18 
19 #include "gmock/gmock.h"
20 #include "test/test_fixture.h"
21 #include "test/unit_spirv.h"
22 #include "test/val/val_fixtures.h"
23 
24 // NOTE: The tests in this file are ONLY testing ID usage, there for the input
25 // SPIR-V does not follow the logical layout rules from the spec in all cases in
26 // order to makes the tests smaller. Validation of the whole module is handled
27 // in stages, ID validation is only one of these stages. All validation stages
28 // are stand alone.
29 
30 namespace spvtools {
31 namespace val {
32 namespace {
33 
34 using spvtest::ScopedContext;
35 using ::testing::HasSubstr;
36 using ::testing::ValuesIn;
37 
38 using ValidateIdWithMessage = spvtest::ValidateBase<bool>;
39 
40 std::string kOpCapabilitySetupWithoutVector16 = R"(
41      OpCapability Shader
42      OpCapability Linkage
43      OpCapability Addresses
44      OpCapability Int8
45      OpCapability Int16
46      OpCapability Int64
47      OpCapability Float64
48      OpCapability LiteralSampler
49      OpCapability Pipes
50      OpCapability DeviceEnqueue
51 )";
52 
53 std::string kOpCapabilitySetup = R"(
54      OpCapability Shader
55      OpCapability Linkage
56      OpCapability Addresses
57      OpCapability Int8
58      OpCapability Int16
59      OpCapability Int64
60      OpCapability Float64
61      OpCapability LiteralSampler
62      OpCapability Pipes
63      OpCapability DeviceEnqueue
64      OpCapability Vector16
65 )";
66 
67 std::string kOpVariablePtrSetUp = R"(
68      OpCapability VariablePointers
69      OpExtension "SPV_KHR_variable_pointers"
70 )";
71 
72 std::string kGLSL450MemoryModel =
73     kOpCapabilitySetup + kOpVariablePtrSetUp + R"(
74      OpMemoryModel Logical GLSL450
75 )";
76 
77 std::string kGLSL450MemoryModelWithoutVector16 =
78     kOpCapabilitySetupWithoutVector16 + kOpVariablePtrSetUp + R"(
79      OpMemoryModel Logical GLSL450
80 )";
81 
82 std::string kNoKernelGLSL450MemoryModel = R"(
83      OpCapability Shader
84      OpCapability Linkage
85      OpCapability Addresses
86      OpCapability Int8
87      OpCapability Int16
88      OpCapability Int64
89      OpCapability Float64
90      OpMemoryModel Logical GLSL450
91 )";
92 
93 std::string kOpenCLMemoryModel32 = R"(
94      OpCapability Addresses
95      OpCapability Linkage
96      OpCapability Kernel
97 %1 = OpExtInstImport "OpenCL.std"
98      OpMemoryModel Physical32 OpenCL
99 )";
100 
101 std::string kOpenCLMemoryModel64 = R"(
102      OpCapability Addresses
103      OpCapability Linkage
104      OpCapability Kernel
105      OpCapability Int64
106 %1 = OpExtInstImport "OpenCL.std"
107      OpMemoryModel Physical64 OpenCL
108 )";
109 
110 std::string sampledImageSetup = R"(
111                     %void = OpTypeVoid
112             %typeFuncVoid = OpTypeFunction %void
113                    %float = OpTypeFloat 32
114                  %v4float = OpTypeVector %float 4
115               %image_type = OpTypeImage %float 2D 0 0 0 1 Unknown
116 %_ptr_UniformConstant_img = OpTypePointer UniformConstant %image_type
117                      %tex = OpVariable %_ptr_UniformConstant_img UniformConstant
118             %sampler_type = OpTypeSampler
119 %_ptr_UniformConstant_sam = OpTypePointer UniformConstant %sampler_type
120                        %s = OpVariable %_ptr_UniformConstant_sam UniformConstant
121       %sampled_image_type = OpTypeSampledImage %image_type
122                  %v2float = OpTypeVector %float 2
123                  %float_1 = OpConstant %float 1
124                  %float_2 = OpConstant %float 2
125            %const_vec_1_1 = OpConstantComposite %v2float %float_1 %float_1
126            %const_vec_2_2 = OpConstantComposite %v2float %float_2 %float_2
127                %bool_type = OpTypeBool
128                %spec_true = OpSpecConstantTrue %bool_type
129                     %main = OpFunction %void None %typeFuncVoid
130                  %label_1 = OpLabel
131               %image_inst = OpLoad %image_type %tex
132             %sampler_inst = OpLoad %sampler_type %s
133 )";
134 
135 std::string BranchConditionalSetup = R"(
136                OpCapability Shader
137           %1 = OpExtInstImport "GLSL.std.450"
138                OpMemoryModel Logical GLSL450
139                OpEntryPoint Fragment %main "main"
140                OpExecutionMode %main OriginUpperLeft
141                OpSource GLSL 140
142                OpName %main "main"
143 
144              ; type definitions
145        %bool = OpTypeBool
146        %uint = OpTypeInt 32 0
147         %int = OpTypeInt 32 1
148       %float = OpTypeFloat 32
149     %v4float = OpTypeVector %float 4
150 
151              ; constants
152        %true = OpConstantTrue %bool
153          %i0 = OpConstant %int 0
154          %i1 = OpConstant %int 1
155          %f0 = OpConstant %float 0
156          %f1 = OpConstant %float 1
157 
158 
159              ; main function header
160        %void = OpTypeVoid
161    %voidfunc = OpTypeFunction %void
162        %main = OpFunction %void None %voidfunc
163       %lmain = OpLabel
164 )";
165 
166 std::string BranchConditionalTail = R"(
167    %target_t = OpLabel
168                OpNop
169                OpBranch %end
170    %target_f = OpLabel
171                OpNop
172                OpBranch %end
173 
174         %end = OpLabel
175 
176                OpReturn
177                OpFunctionEnd
178 )";
179 
180 // TODO: OpUndef
181 
TEST_F(ValidateIdWithMessage,OpName)182 TEST_F(ValidateIdWithMessage, OpName) {
183   std::string spirv = kGLSL450MemoryModel + R"(
184      OpName %2 "name"
185 %1 = OpTypeInt 32 0
186 %2 = OpTypePointer UniformConstant %1
187 %3 = OpVariable %2 UniformConstant)";
188   CompileSuccessfully(spirv.c_str());
189   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
190 }
191 
TEST_F(ValidateIdWithMessage,OpMemberNameGood)192 TEST_F(ValidateIdWithMessage, OpMemberNameGood) {
193   std::string spirv = kGLSL450MemoryModel + R"(
194      OpMemberName %2 0 "foo"
195 %1 = OpTypeInt 32 0
196 %2 = OpTypeStruct %1)";
197   CompileSuccessfully(spirv.c_str());
198   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
199 }
TEST_F(ValidateIdWithMessage,OpMemberNameTypeBad)200 TEST_F(ValidateIdWithMessage, OpMemberNameTypeBad) {
201   std::string spirv = kGLSL450MemoryModel + R"(
202      OpMemberName %1 0 "foo"
203 %1 = OpTypeInt 32 0)";
204   CompileSuccessfully(spirv.c_str());
205   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
206   EXPECT_THAT(
207       getDiagnosticString(),
208       HasSubstr("OpMemberName Type <id> '1[%uint]' is not a struct type."));
209 }
TEST_F(ValidateIdWithMessage,OpMemberNameMemberBad)210 TEST_F(ValidateIdWithMessage, OpMemberNameMemberBad) {
211   std::string spirv = kGLSL450MemoryModel + R"(
212      OpMemberName %1 1 "foo"
213 %2 = OpTypeInt 32 0
214 %1 = OpTypeStruct %2)";
215   CompileSuccessfully(spirv.c_str());
216   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
217   EXPECT_THAT(
218       getDiagnosticString(),
219       HasSubstr("OpMemberName Member <id> '1[%_struct_1]' index is larger "
220                 "than Type <id> '1[%_struct_1]'s member count."));
221 }
222 
TEST_F(ValidateIdWithMessage,OpLineGood)223 TEST_F(ValidateIdWithMessage, OpLineGood) {
224   std::string spirv = kGLSL450MemoryModel + R"(
225 %1 = OpString "/path/to/source.file"
226      OpLine %1 0 0
227 %2 = OpTypeInt 32 0
228 %3 = OpTypePointer Input %2
229 %4 = OpVariable %3 Input)";
230   CompileSuccessfully(spirv.c_str());
231   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
232 }
233 
TEST_F(ValidateIdWithMessage,OpLineFileBad)234 TEST_F(ValidateIdWithMessage, OpLineFileBad) {
235   std::string spirv = kGLSL450MemoryModel + R"(
236   %1 = OpTypeInt 32 0
237      OpLine %1 0 0
238   )";
239   CompileSuccessfully(spirv.c_str());
240   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
241   EXPECT_THAT(getDiagnosticString(),
242               HasSubstr("OpLine Target <id> '1[%uint]' is not an OpString."));
243 }
244 
TEST_F(ValidateIdWithMessage,OpDecorateGood)245 TEST_F(ValidateIdWithMessage, OpDecorateGood) {
246   std::string spirv = kGLSL450MemoryModel + R"(
247      OpDecorate %2 GLSLShared
248 %1 = OpTypeInt 64 0
249 %2 = OpTypeStruct %1 %1)";
250   CompileSuccessfully(spirv.c_str());
251   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
252 }
TEST_F(ValidateIdWithMessage,OpDecorateBad)253 TEST_F(ValidateIdWithMessage, OpDecorateBad) {
254   std::string spirv = kGLSL450MemoryModel + R"(
255 OpDecorate %1 GLSLShared)";
256   CompileSuccessfully(spirv.c_str());
257   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
258   EXPECT_THAT(getDiagnosticString(),
259               HasSubstr("forward referenced IDs have not been defined"));
260 }
261 
TEST_F(ValidateIdWithMessage,OpMemberDecorateGood)262 TEST_F(ValidateIdWithMessage, OpMemberDecorateGood) {
263   std::string spirv = kGLSL450MemoryModel + R"(
264      OpMemberDecorate %2 0 RelaxedPrecision
265 %1 = OpTypeInt 32 0
266 %2 = OpTypeStruct %1 %1)";
267   CompileSuccessfully(spirv.c_str());
268   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
269 }
TEST_F(ValidateIdWithMessage,OpMemberDecorateBad)270 TEST_F(ValidateIdWithMessage, OpMemberDecorateBad) {
271   std::string spirv = kGLSL450MemoryModel + R"(
272      OpMemberDecorate %1 0 RelaxedPrecision
273 %1 = OpTypeInt 32 0)";
274   CompileSuccessfully(spirv.c_str());
275   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
276   EXPECT_THAT(getDiagnosticString(),
277               HasSubstr("OpMemberDecorate Structure type <id> '1[%uint]' is "
278                         "not a struct type."));
279 }
TEST_F(ValidateIdWithMessage,OpMemberDecorateMemberBad)280 TEST_F(ValidateIdWithMessage, OpMemberDecorateMemberBad) {
281   std::string spirv = kGLSL450MemoryModel + R"(
282      OpMemberDecorate %1 3 RelaxedPrecision
283 %int = OpTypeInt 32 0
284 %1 = OpTypeStruct %int %int)";
285   CompileSuccessfully(spirv.c_str());
286   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
287   EXPECT_THAT(getDiagnosticString(),
288               HasSubstr("Index 3 provided in OpMemberDecorate for struct <id> "
289                         "1[%_struct_1] is out of bounds. The structure has 2 "
290                         "members. Largest valid index is 1."));
291 }
292 
TEST_F(ValidateIdWithMessage,OpGroupDecorateGood)293 TEST_F(ValidateIdWithMessage, OpGroupDecorateGood) {
294   std::string spirv = kGLSL450MemoryModel + R"(
295 %1 = OpDecorationGroup
296      OpDecorate %1 RelaxedPrecision
297      OpDecorate %1 GLSLShared
298      OpGroupDecorate %1 %3 %4
299 %2 = OpTypeInt 32 0
300 %3 = OpConstant %2 42
301 %4 = OpConstant %2 23)";
302   CompileSuccessfully(spirv.c_str());
303   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
304 }
TEST_F(ValidateIdWithMessage,OpDecorationGroupBad)305 TEST_F(ValidateIdWithMessage, OpDecorationGroupBad) {
306   std::string spirv = kGLSL450MemoryModel + R"(
307 %1 = OpDecorationGroup
308      OpDecorate %1 RelaxedPrecision
309      OpDecorate %1 GLSLShared
310      OpMemberDecorate %1 0 Constant
311     )";
312   CompileSuccessfully(spirv.c_str());
313   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
314   EXPECT_THAT(getDiagnosticString(),
315               HasSubstr("Result id of OpDecorationGroup can only "
316                         "be targeted by OpName, OpGroupDecorate, "
317                         "OpDecorate, OpDecorateId, and OpGroupMemberDecorate"));
318 }
TEST_F(ValidateIdWithMessage,OpGroupDecorateDecorationGroupBad)319 TEST_F(ValidateIdWithMessage, OpGroupDecorateDecorationGroupBad) {
320   std::string spirv = R"(
321     OpCapability Shader
322     OpCapability Linkage
323     %1 = OpExtInstImport "GLSL.std.450"
324     OpMemoryModel Logical GLSL450
325     OpGroupDecorate %1 %2 %3
326 %2 = OpTypeInt 32 0
327 %3 = OpConstant %2 42)";
328   CompileSuccessfully(spirv.c_str());
329   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
330   EXPECT_THAT(getDiagnosticString(),
331               HasSubstr("OpGroupDecorate Decoration group <id> '1[%1]' is not "
332                         "a decoration group."));
333 }
TEST_F(ValidateIdWithMessage,OpGroupDecorateTargetBad)334 TEST_F(ValidateIdWithMessage, OpGroupDecorateTargetBad) {
335   std::string spirv = kGLSL450MemoryModel + R"(
336 %1 = OpDecorationGroup
337      OpDecorate %1 RelaxedPrecision
338      OpDecorate %1 GLSLShared
339      OpGroupDecorate %1 %3
340 %2 = OpTypeInt 32 0)";
341   CompileSuccessfully(spirv.c_str());
342   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
343   EXPECT_THAT(getDiagnosticString(),
344               HasSubstr("forward referenced IDs have not been defined"));
345 }
TEST_F(ValidateIdWithMessage,OpGroupMemberDecorateDecorationGroupBad)346 TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateDecorationGroupBad) {
347   std::string spirv = R"(
348     OpCapability Shader
349     OpCapability Linkage
350     %1 = OpExtInstImport "GLSL.std.450"
351     OpMemoryModel Logical GLSL450
352     OpGroupMemberDecorate %1 %2 0
353 %2 = OpTypeInt 32 0)";
354   CompileSuccessfully(spirv.c_str());
355   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
356   EXPECT_THAT(getDiagnosticString(),
357               HasSubstr("OpGroupMemberDecorate Decoration group <id> '1[%1]' "
358                         "is not a decoration group."));
359 }
TEST_F(ValidateIdWithMessage,OpGroupMemberDecorateIdNotStructBad)360 TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIdNotStructBad) {
361   std::string spirv = kGLSL450MemoryModel + R"(
362      %1 = OpDecorationGroup
363      OpGroupMemberDecorate %1 %2 0
364 %2 = OpTypeInt 32 0)";
365   CompileSuccessfully(spirv.c_str());
366   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
367   EXPECT_THAT(getDiagnosticString(),
368               HasSubstr("OpGroupMemberDecorate Structure type <id> '2[%uint]' "
369                         "is not a struct type."));
370 }
TEST_F(ValidateIdWithMessage,OpGroupMemberDecorateIndexOutOfBoundBad)371 TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIndexOutOfBoundBad) {
372   std::string spirv = kGLSL450MemoryModel + R"(
373   OpDecorate %1 Offset 0
374   %1 = OpDecorationGroup
375   OpGroupMemberDecorate %1 %struct 3
376 %float  = OpTypeFloat 32
377 %struct = OpTypeStruct %float %float %float
378 )";
379   CompileSuccessfully(spirv.c_str());
380   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
381   EXPECT_THAT(getDiagnosticString(),
382               HasSubstr("Index 3 provided in OpGroupMemberDecorate for struct "
383                         "<id> 2[%_struct_2] is out of bounds. The structure "
384                         "has 3 members. Largest valid index is 2."));
385 }
386 
387 // TODO: OpExtInst
388 
TEST_F(ValidateIdWithMessage,OpEntryPointGood)389 TEST_F(ValidateIdWithMessage, OpEntryPointGood) {
390   std::string spirv = kGLSL450MemoryModel + R"(
391      OpEntryPoint GLCompute %3 ""
392 %1 = OpTypeVoid
393 %2 = OpTypeFunction %1
394 %3 = OpFunction %1 None %2
395 %4 = OpLabel
396      OpReturn
397      OpFunctionEnd
398 )";
399   CompileSuccessfully(spirv.c_str());
400   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
401 }
TEST_F(ValidateIdWithMessage,OpEntryPointFunctionBad)402 TEST_F(ValidateIdWithMessage, OpEntryPointFunctionBad) {
403   std::string spirv = kGLSL450MemoryModel + R"(
404      OpEntryPoint GLCompute %1 ""
405 %1 = OpTypeVoid)";
406   CompileSuccessfully(spirv.c_str());
407   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
408   EXPECT_THAT(getDiagnosticString(),
409               HasSubstr("OpEntryPoint Entry Point <id> '1[%void]' is not a "
410                         "function."));
411 }
TEST_F(ValidateIdWithMessage,OpEntryPointParameterCountBad)412 TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) {
413   std::string spirv = kGLSL450MemoryModel + R"(
414      OpEntryPoint GLCompute %3 ""
415 %1 = OpTypeVoid
416 %2 = OpTypeFunction %1 %1
417 %3 = OpFunction %1 None %2
418 %4 = OpLabel
419      OpReturn
420      OpFunctionEnd)";
421   CompileSuccessfully(spirv.c_str());
422   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
423   EXPECT_THAT(getDiagnosticString(),
424               HasSubstr("OpEntryPoint Entry Point <id> '1[%1]'s function "
425                         "parameter count is not zero"));
426 }
TEST_F(ValidateIdWithMessage,OpEntryPointReturnTypeBad)427 TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) {
428   std::string spirv = kGLSL450MemoryModel + R"(
429      OpEntryPoint GLCompute %3 ""
430 %1 = OpTypeInt 32 0
431 %ret = OpConstant %1 0
432 %2 = OpTypeFunction %1
433 %3 = OpFunction %1 None %2
434 %4 = OpLabel
435      OpReturnValue %ret
436      OpFunctionEnd)";
437   CompileSuccessfully(spirv.c_str());
438   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
439   EXPECT_THAT(getDiagnosticString(),
440               HasSubstr("OpEntryPoint Entry Point <id> '1[%1]'s function "
441                         "return type is not void."));
442 }
443 
TEST_F(ValidateIdWithMessage,OpEntryPointInterfaceIsNotVariableTypeBad)444 TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) {
445   std::string spirv = R"(
446                OpCapability Shader
447                OpCapability Geometry
448                OpMemoryModel Logical GLSL450
449                OpEntryPoint Geometry %main "main" %ptr_builtin_1
450                OpExecutionMode %main InputPoints
451                OpExecutionMode %main OutputPoints
452                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
453       %int = OpTypeInt 32 1
454      %void = OpTypeVoid
455      %func = OpTypeFunction %void
456  %struct_1 = OpTypeStruct %int
457 %ptr_builtin_1 = OpTypePointer Input %struct_1
458        %main = OpFunction %void None %func
459           %5 = OpLabel
460                OpReturn
461                OpFunctionEnd
462   )";
463   CompileSuccessfully(spirv);
464   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
465   EXPECT_THAT(getDiagnosticString(),
466               HasSubstr("Interfaces passed to OpEntryPoint must be of type "
467                         "OpTypeVariable. Found OpTypePointer."));
468 }
469 
TEST_F(ValidateIdWithMessage,OpEntryPointInterfaceStorageClassBad)470 TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceStorageClassBad) {
471   std::string spirv = R"(
472                OpCapability Shader
473                OpCapability Geometry
474                OpMemoryModel Logical GLSL450
475                OpEntryPoint Geometry %main "main" %in_1
476                OpExecutionMode %main InputPoints
477                OpExecutionMode %main OutputPoints
478                OpMemberDecorate %struct_1 0 BuiltIn InvocationId
479       %int = OpTypeInt 32 1
480      %void = OpTypeVoid
481      %func = OpTypeFunction %void
482  %struct_1 = OpTypeStruct %int
483 %ptr_builtin_1 = OpTypePointer Uniform %struct_1
484        %in_1 = OpVariable %ptr_builtin_1 Uniform
485        %main = OpFunction %void None %func
486           %5 = OpLabel
487                OpReturn
488                OpFunctionEnd
489   )";
490   CompileSuccessfully(spirv);
491   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
492   EXPECT_THAT(getDiagnosticString(),
493               HasSubstr("OpEntryPoint interfaces must be OpVariables with "
494                         "Storage Class of Input(1) or Output(3). Found Storage "
495                         "Class 2 for Entry Point id 1."));
496 }
497 
TEST_F(ValidateIdWithMessage,OpExecutionModeGood)498 TEST_F(ValidateIdWithMessage, OpExecutionModeGood) {
499   std::string spirv = kGLSL450MemoryModel + R"(
500      OpEntryPoint GLCompute %3 ""
501      OpExecutionMode %3 LocalSize 1 1 1
502 %1 = OpTypeVoid
503 %2 = OpTypeFunction %1
504 %3 = OpFunction %1 None %2
505 %4 = OpLabel
506      OpReturn
507      OpFunctionEnd)";
508   CompileSuccessfully(spirv.c_str());
509   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
510 }
511 
TEST_F(ValidateIdWithMessage,OpExecutionModeEntryPointMissing)512 TEST_F(ValidateIdWithMessage, OpExecutionModeEntryPointMissing) {
513   std::string spirv = kGLSL450MemoryModel + R"(
514      OpExecutionMode %3 LocalSize 1 1 1
515 %1 = OpTypeVoid
516 %2 = OpTypeFunction %1
517 %3 = OpFunction %1 None %2
518 %4 = OpLabel
519      OpReturn
520      OpFunctionEnd)";
521   CompileSuccessfully(spirv.c_str());
522   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
523   EXPECT_THAT(getDiagnosticString(),
524               HasSubstr("OpExecutionMode Entry Point <id> '1[%1]' is not the "
525                         "Entry Point operand of an OpEntryPoint."));
526 }
527 
TEST_F(ValidateIdWithMessage,OpExecutionModeEntryPointBad)528 TEST_F(ValidateIdWithMessage, OpExecutionModeEntryPointBad) {
529   std::string spirv = kGLSL450MemoryModel + R"(
530      OpEntryPoint GLCompute %3 "" %a
531      OpExecutionMode %a LocalSize 1 1 1
532 %void = OpTypeVoid
533 %ptr = OpTypePointer Input %void
534 %a = OpVariable %ptr Input
535 %2 = OpTypeFunction %void
536 %3 = OpFunction %void None %2
537 %4 = OpLabel
538      OpReturn
539      OpFunctionEnd)";
540   CompileSuccessfully(spirv.c_str());
541   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
542   EXPECT_THAT(getDiagnosticString(),
543               HasSubstr("OpExecutionMode Entry Point <id> '2[%2]' is not the "
544                         "Entry Point operand of an OpEntryPoint."));
545 }
546 
TEST_F(ValidateIdWithMessage,OpTypeVectorFloat)547 TEST_F(ValidateIdWithMessage, OpTypeVectorFloat) {
548   std::string spirv = kGLSL450MemoryModel + R"(
549 %1 = OpTypeFloat 32
550 %2 = OpTypeVector %1 4)";
551   CompileSuccessfully(spirv.c_str());
552   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
553 }
554 
TEST_F(ValidateIdWithMessage,OpTypeVectorInt)555 TEST_F(ValidateIdWithMessage, OpTypeVectorInt) {
556   std::string spirv = kGLSL450MemoryModel + R"(
557 %1 = OpTypeInt 32 0
558 %2 = OpTypeVector %1 4)";
559   CompileSuccessfully(spirv.c_str());
560   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
561 }
562 
TEST_F(ValidateIdWithMessage,OpTypeVectorUInt)563 TEST_F(ValidateIdWithMessage, OpTypeVectorUInt) {
564   std::string spirv = kGLSL450MemoryModel + R"(
565 %1 = OpTypeInt 64 0
566 %2 = OpTypeVector %1 4)";
567   CompileSuccessfully(spirv.c_str());
568   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
569 }
570 
TEST_F(ValidateIdWithMessage,OpTypeVectorBool)571 TEST_F(ValidateIdWithMessage, OpTypeVectorBool) {
572   std::string spirv = kGLSL450MemoryModel + R"(
573 %1 = OpTypeBool
574 %2 = OpTypeVector %1 4)";
575   CompileSuccessfully(spirv.c_str());
576   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
577 }
578 
TEST_F(ValidateIdWithMessage,OpTypeVectorComponentTypeBad)579 TEST_F(ValidateIdWithMessage, OpTypeVectorComponentTypeBad) {
580   std::string spirv = kGLSL450MemoryModel + R"(
581 %1 = OpTypeFloat 32
582 %2 = OpTypePointer UniformConstant %1
583 %3 = OpTypeVector %2 4)";
584   CompileSuccessfully(spirv.c_str());
585   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
586   EXPECT_THAT(
587       getDiagnosticString(),
588       HasSubstr("OpTypeVector Component Type <id> "
589                 "'2[%_ptr_UniformConstant_float]' is not a scalar type."));
590 }
591 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountLessThanTwoBad)592 TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountLessThanTwoBad) {
593   std::string spirv = kGLSL450MemoryModel + R"(
594 %1 = OpTypeFloat 32
595 %2 = OpTypeVector %1 1)";
596   CompileSuccessfully(spirv.c_str());
597   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
598   EXPECT_THAT(
599       getDiagnosticString(),
600       HasSubstr("Illegal number of components (1) for TypeVector\n  %v1float = "
601                 "OpTypeVector %float 1\n"));
602 }
603 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountGreaterThanFourBad)604 TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountGreaterThanFourBad) {
605   std::string spirv = kGLSL450MemoryModel + R"(
606 %1 = OpTypeFloat 32
607 %2 = OpTypeVector %1 5)";
608   CompileSuccessfully(spirv.c_str());
609   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
610   EXPECT_THAT(
611       getDiagnosticString(),
612       HasSubstr("Illegal number of components (5) for TypeVector\n  %v5float = "
613                 "OpTypeVector %float 5\n"));
614 }
615 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountEightWithoutVector16Bad)616 TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountEightWithoutVector16Bad) {
617   std::string spirv = kGLSL450MemoryModelWithoutVector16 + R"(
618 %1 = OpTypeFloat 32
619 %2 = OpTypeVector %1 8)";
620 
621   CompileSuccessfully(spirv.c_str());
622   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
623   EXPECT_THAT(
624       getDiagnosticString(),
625       HasSubstr("Having 8 components for TypeVector requires the Vector16 "
626                 "capability\n  %v8float = OpTypeVector %float 8\n"));
627 }
628 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountSixteenWithoutVector16Bad)629 TEST_F(ValidateIdWithMessage,
630        OpTypeVectorColumnCountSixteenWithoutVector16Bad) {
631   std::string spirv = kGLSL450MemoryModelWithoutVector16 + R"(
632 %1 = OpTypeFloat 32
633 %2 = OpTypeVector %1 16)";
634 
635   CompileSuccessfully(spirv.c_str());
636   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
637   EXPECT_THAT(
638       getDiagnosticString(),
639       HasSubstr("Having 16 components for TypeVector requires the Vector16 "
640                 "capability\n  %v16float = OpTypeVector %float 16\n"));
641 }
642 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountOfEightWithVector16Good)643 TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountOfEightWithVector16Good) {
644   std::string spirv = kGLSL450MemoryModel + R"(
645 %1 = OpTypeFloat 32
646 %2 = OpTypeVector %1 8)";
647   CompileSuccessfully(spirv.c_str());
648   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
649 }
650 
TEST_F(ValidateIdWithMessage,OpTypeVectorColumnCountOfSixteenWithVector16Good)651 TEST_F(ValidateIdWithMessage,
652        OpTypeVectorColumnCountOfSixteenWithVector16Good) {
653   std::string spirv = kGLSL450MemoryModel + R"(
654 %1 = OpTypeFloat 32
655 %2 = OpTypeVector %1 16)";
656   CompileSuccessfully(spirv.c_str());
657   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
658 }
659 
TEST_F(ValidateIdWithMessage,OpTypeMatrixGood)660 TEST_F(ValidateIdWithMessage, OpTypeMatrixGood) {
661   std::string spirv = kGLSL450MemoryModel + R"(
662 %1 = OpTypeFloat 32
663 %2 = OpTypeVector %1 2
664 %3 = OpTypeMatrix %2 3)";
665   CompileSuccessfully(spirv.c_str());
666   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
667 }
668 
TEST_F(ValidateIdWithMessage,OpTypeMatrixColumnTypeNonVectorBad)669 TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnTypeNonVectorBad) {
670   std::string spirv = kGLSL450MemoryModel + R"(
671 %1 = OpTypeFloat 32
672 %2 = OpTypeMatrix %1 3)";
673   CompileSuccessfully(spirv.c_str());
674   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
675   EXPECT_THAT(
676       getDiagnosticString(),
677       HasSubstr("olumns in a matrix must be of type vector.\n  %mat3float = "
678                 "OpTypeMatrix %float 3\n"));
679 }
680 
TEST_F(ValidateIdWithMessage,OpTypeMatrixVectorTypeNonFloatBad)681 TEST_F(ValidateIdWithMessage, OpTypeMatrixVectorTypeNonFloatBad) {
682   std::string spirv = kGLSL450MemoryModel + R"(
683 %1 = OpTypeInt 16 0
684 %2 = OpTypeVector %1 2
685 %3 = OpTypeMatrix %2 2)";
686   CompileSuccessfully(spirv.c_str());
687   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
688   EXPECT_THAT(
689       getDiagnosticString(),
690       HasSubstr("Matrix types can only be parameterized with floating-point "
691                 "types.\n  %mat2v2ushort = OpTypeMatrix %v2ushort 2\n"));
692 }
693 
TEST_F(ValidateIdWithMessage,OpTypeMatrixColumnCountLessThanTwoBad)694 TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnCountLessThanTwoBad) {
695   std::string spirv = kGLSL450MemoryModel + R"(
696 %1 = OpTypeFloat 32
697 %2 = OpTypeVector %1 2
698 %3 = OpTypeMatrix %2 1)";
699   CompileSuccessfully(spirv.c_str());
700   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
701   EXPECT_THAT(
702       getDiagnosticString(),
703       HasSubstr("Matrix types can only be parameterized as having only 2, 3, "
704                 "or 4 columns.\n  %mat1v2float = OpTypeMatrix %v2float 1\n"));
705 }
706 
TEST_F(ValidateIdWithMessage,OpTypeMatrixColumnCountGreaterThanFourBad)707 TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnCountGreaterThanFourBad) {
708   std::string spirv = kGLSL450MemoryModel + R"(
709 %1 = OpTypeFloat 32
710 %2 = OpTypeVector %1 2
711 %3 = OpTypeMatrix %2 8)";
712   CompileSuccessfully(spirv.c_str());
713   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
714   EXPECT_THAT(
715       getDiagnosticString(),
716       HasSubstr("Matrix types can only be parameterized as having only 2, 3, "
717                 "or 4 columns.\n  %mat8v2float = OpTypeMatrix %v2float 8\n"));
718 }
719 
TEST_F(ValidateIdWithMessage,OpTypeSamplerGood)720 TEST_F(ValidateIdWithMessage, OpTypeSamplerGood) {
721   // In Rev31, OpTypeSampler takes no arguments.
722   std::string spirv = kGLSL450MemoryModel + R"(
723 %s = OpTypeSampler)";
724   CompileSuccessfully(spirv.c_str());
725   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
726 }
727 
TEST_F(ValidateIdWithMessage,OpTypeArrayGood)728 TEST_F(ValidateIdWithMessage, OpTypeArrayGood) {
729   std::string spirv = kGLSL450MemoryModel + R"(
730 %1 = OpTypeInt 32 0
731 %2 = OpConstant %1 1
732 %3 = OpTypeArray %1 %2)";
733   CompileSuccessfully(spirv.c_str());
734   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
735 }
736 
TEST_F(ValidateIdWithMessage,OpTypeArrayElementTypeBad)737 TEST_F(ValidateIdWithMessage, OpTypeArrayElementTypeBad) {
738   std::string spirv = kGLSL450MemoryModel + R"(
739 %1 = OpTypeInt 32 0
740 %2 = OpConstant %1 1
741 %3 = OpTypeArray %2 %2)";
742   CompileSuccessfully(spirv.c_str());
743   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
744   EXPECT_THAT(getDiagnosticString(),
745               HasSubstr("OpTypeArray Element Type <id> '2[%uint_1]' is not a "
746                         "type."));
747 }
748 
749 // Signed or unsigned.
750 enum Signed { kSigned, kUnsigned };
751 
752 // Creates an assembly module declaring OpTypeArray with the given length.
MakeArrayLength(const std::string & len,Signed isSigned,int width,int max_int_width=64,bool use_vulkan_memory_model=false)753 std::string MakeArrayLength(const std::string& len, Signed isSigned, int width,
754                             int max_int_width = 64,
755                             bool use_vulkan_memory_model = false) {
756   std::ostringstream ss;
757   ss << R"(
758     OpCapability Shader
759   )";
760   if (use_vulkan_memory_model) {
761     ss << " OpCapability VulkanMemoryModel\n";
762   }
763   if (width == 16) {
764     ss << " OpCapability Int16\n";
765   }
766   if (max_int_width > 32) {
767     ss << "\n  OpCapability Int64\n";
768   }
769   if (use_vulkan_memory_model) {
770     ss << " OpExtension \"SPV_KHR_vulkan_memory_model\"\n";
771     ss << "OpMemoryModel Logical Vulkan\n";
772   } else {
773     ss << "OpMemoryModel Logical GLSL450\n";
774   }
775   ss << "OpEntryPoint GLCompute %main \"main\"\n";
776   ss << "OpExecutionMode %main LocalSize 1 1 1\n";
777   ss << " %t = OpTypeInt " << width << (isSigned == kSigned ? " 1" : " 0");
778   ss << " %l = OpConstant %t " << len;
779   ss << " %a = OpTypeArray %t %l";
780   ss << " %void = OpTypeVoid \n"
781         " %voidfn = OpTypeFunction %void \n"
782         " %main = OpFunction %void None %voidfn \n"
783         " %entry = OpLabel\n"
784         " OpReturn\n"
785         " OpFunctionEnd\n";
786   return ss.str();
787 }
788 
789 // Tests OpTypeArray.  Parameter is the width (in bits) of the array-length's
790 // type.
791 class OpTypeArrayLengthTest
792     : public spvtest::TextToBinaryTestBase<::testing::TestWithParam<int>> {
793  protected:
OpTypeArrayLengthTest()794   OpTypeArrayLengthTest()
795       : env_(SPV_ENV_UNIVERSAL_1_0),
796         position_(spv_position_t{0, 0, 0}),
797         diagnostic_(spvDiagnosticCreate(&position_, "")) {}
798 
~OpTypeArrayLengthTest()799   ~OpTypeArrayLengthTest() { spvDiagnosticDestroy(diagnostic_); }
800 
801   // Runs spvValidate() on v, printing any errors via spvDiagnosticPrint().
Val(const SpirvVector & v,const std::string & expected_err="")802   spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") {
803     spv_const_binary_t cbinary{v.data(), v.size()};
804     spvDiagnosticDestroy(diagnostic_);
805     diagnostic_ = nullptr;
806     const auto status =
807         spvValidate(ScopedContext(env_).context, &cbinary, &diagnostic_);
808     if (status != SPV_SUCCESS) {
809       spvDiagnosticPrint(diagnostic_);
810       EXPECT_THAT(std::string(diagnostic_->error),
811                   testing::ContainsRegex(expected_err));
812     }
813     return status;
814   }
815 
816  protected:
817   spv_target_env env_;
818 
819  private:
820   spv_position_t position_;  // For creating diagnostic_.
821   spv_diagnostic diagnostic_;
822 };
823 
TEST_P(OpTypeArrayLengthTest,LengthPositiveSmall)824 TEST_P(OpTypeArrayLengthTest, LengthPositiveSmall) {
825   const int width = GetParam();
826   EXPECT_EQ(SPV_SUCCESS,
827             Val(CompileSuccessfully(MakeArrayLength("1", kSigned, width))));
828   EXPECT_EQ(SPV_SUCCESS,
829             Val(CompileSuccessfully(MakeArrayLength("1", kUnsigned, width))));
830   EXPECT_EQ(SPV_SUCCESS,
831             Val(CompileSuccessfully(MakeArrayLength("2", kSigned, width))));
832   EXPECT_EQ(SPV_SUCCESS,
833             Val(CompileSuccessfully(MakeArrayLength("2", kUnsigned, width))));
834   EXPECT_EQ(SPV_SUCCESS,
835             Val(CompileSuccessfully(MakeArrayLength("55", kSigned, width))));
836   EXPECT_EQ(SPV_SUCCESS,
837             Val(CompileSuccessfully(MakeArrayLength("55", kUnsigned, width))));
838   const std::string fpad(width / 4 - 1, 'F');
839   EXPECT_EQ(
840       SPV_SUCCESS,
841       Val(CompileSuccessfully(MakeArrayLength("0x7" + fpad, kSigned, width))))
842       << MakeArrayLength("0x7" + fpad, kSigned, width);
843 }
844 
TEST_P(OpTypeArrayLengthTest,LengthZero)845 TEST_P(OpTypeArrayLengthTest, LengthZero) {
846   const int width = GetParam();
847   EXPECT_EQ(SPV_ERROR_INVALID_ID,
848             Val(CompileSuccessfully(MakeArrayLength("0", kSigned, width)),
849                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
850                 "least 1."));
851   EXPECT_EQ(SPV_ERROR_INVALID_ID,
852             Val(CompileSuccessfully(MakeArrayLength("0", kUnsigned, width)),
853                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
854                 "least 1."));
855 }
856 
TEST_P(OpTypeArrayLengthTest,LengthNegative)857 TEST_P(OpTypeArrayLengthTest, LengthNegative) {
858   const int width = GetParam();
859   EXPECT_EQ(SPV_ERROR_INVALID_ID,
860             Val(CompileSuccessfully(MakeArrayLength("-1", kSigned, width)),
861                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
862                 "least 1."));
863   EXPECT_EQ(SPV_ERROR_INVALID_ID,
864             Val(CompileSuccessfully(MakeArrayLength("-2", kSigned, width)),
865                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
866                 "least 1."));
867   EXPECT_EQ(SPV_ERROR_INVALID_ID,
868             Val(CompileSuccessfully(MakeArrayLength("-123", kSigned, width)),
869                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
870                 "least 1."));
871   const std::string neg_max = "0x8" + std::string(width / 4 - 1, '0');
872   EXPECT_EQ(SPV_ERROR_INVALID_ID,
873             Val(CompileSuccessfully(MakeArrayLength(neg_max, kSigned, width)),
874                 "OpTypeArray Length <id> '3\\[%.*\\]' default value must be at "
875                 "least 1."));
876 }
877 
878 // Returns the string form of an integer of the form 0x80....0 of the
879 // given bit width.
big_num_ending_0(int bit_width)880 std::string big_num_ending_0(int bit_width) {
881   return "0x8" + std::string(bit_width / 4 - 1, '0');
882 }
883 
884 // Returns the string form of an integer of the form 0x80..001 of the
885 // given bit width.
big_num_ending_1(int bit_width)886 std::string big_num_ending_1(int bit_width) {
887   return "0x8" + std::string(bit_width / 4 - 2, '0') + "1";
888 }
889 
TEST_P(OpTypeArrayLengthTest,LengthPositiveHugeEnding0InVulkan)890 TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InVulkan) {
891   env_ = SPV_ENV_VULKAN_1_0;
892   const int width = GetParam();
893   for (int max_int_width : {32, 64}) {
894     if (width > max_int_width) {
895       // Not valid to even make the OpConstant in this case.
896       continue;
897     }
898     const auto module = CompileSuccessfully(MakeArrayLength(
899         big_num_ending_0(width), kUnsigned, width, max_int_width));
900     EXPECT_EQ(SPV_SUCCESS, Val(module));
901   }
902 }
903 
TEST_P(OpTypeArrayLengthTest,LengthPositiveHugeEnding1InVulkan)904 TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InVulkan) {
905   env_ = SPV_ENV_VULKAN_1_0;
906   const int width = GetParam();
907   for (int max_int_width : {32, 64}) {
908     if (width > max_int_width) {
909       // Not valid to even make the OpConstant in this case.
910       continue;
911     }
912     const auto module = CompileSuccessfully(MakeArrayLength(
913         big_num_ending_1(width), kUnsigned, width, max_int_width));
914     EXPECT_EQ(SPV_SUCCESS, Val(module));
915   }
916 }
917 
TEST_P(OpTypeArrayLengthTest,LengthPositiveHugeEnding0InWebGPU)918 TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InWebGPU) {
919   env_ = SPV_ENV_WEBGPU_0;
920   const int width = GetParam();
921   // WebGPU only has 32 bit integers.
922   if (width != 32) return;
923   const int max_int_width = 32;
924   const auto module = CompileSuccessfully(MakeArrayLength(
925       big_num_ending_0(width), kUnsigned, width, max_int_width, true));
926   EXPECT_EQ(SPV_SUCCESS, Val(module));
927 }
928 
TEST_P(OpTypeArrayLengthTest,LengthPositiveHugeEnding1InWebGPU)929 TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InWebGPU) {
930   env_ = SPV_ENV_WEBGPU_0;
931   const int width = GetParam();
932   // WebGPU only has 32 bit integers.
933   if (width != 32) return;
934   const int max_int_width = 32;
935   const auto module = CompileSuccessfully(MakeArrayLength(
936       big_num_ending_1(width), kUnsigned, width, max_int_width, true));
937   EXPECT_EQ(SPV_ERROR_INVALID_ID,
938             Val(module,
939                 "OpTypeArray Length <id> '3\\[%.*\\]' size exceeds max value "
940                 "2147483648 permitted by WebGPU: got 2147483649"));
941 }
942 
943 // The only valid widths for integers are 8, 16, 32, and 64.
944 // Since the Int8 capability requires the Kernel capability, and the Kernel
945 // capability prohibits usage of signed integers, we can skip 8-bit integers
946 // here since the purpose of these tests is to check the validity of
947 // OpTypeArray, not OpTypeInt.
948 INSTANTIATE_TEST_SUITE_P(Widths, OpTypeArrayLengthTest,
949                          ValuesIn(std::vector<int>{16, 32, 64}));
950 
TEST_F(ValidateIdWithMessage,OpTypeArrayLengthNull)951 TEST_F(ValidateIdWithMessage, OpTypeArrayLengthNull) {
952   std::string spirv = kGLSL450MemoryModel + R"(
953 %i32 = OpTypeInt 32 0
954 %len = OpConstantNull %i32
955 %ary = OpTypeArray %i32 %len)";
956   CompileSuccessfully(spirv.c_str());
957   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
958   EXPECT_THAT(
959       getDiagnosticString(),
960       HasSubstr(
961           "OpTypeArray Length <id> '2[%2]' default value must be at least 1."));
962 }
963 
TEST_F(ValidateIdWithMessage,OpTypeArrayLengthSpecConst)964 TEST_F(ValidateIdWithMessage, OpTypeArrayLengthSpecConst) {
965   std::string spirv = kGLSL450MemoryModel + R"(
966 %i32 = OpTypeInt 32 0
967 %len = OpSpecConstant %i32 2
968 %ary = OpTypeArray %i32 %len)";
969   CompileSuccessfully(spirv.c_str());
970   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
971 }
972 
TEST_F(ValidateIdWithMessage,OpTypeArrayLengthSpecConstOp)973 TEST_F(ValidateIdWithMessage, OpTypeArrayLengthSpecConstOp) {
974   std::string spirv = kGLSL450MemoryModel + R"(
975 %i32 = OpTypeInt 32 0
976 %c1 = OpConstant %i32 1
977 %c2 = OpConstant %i32 2
978 %len = OpSpecConstantOp %i32 IAdd %c1 %c2
979 %ary = OpTypeArray %i32 %len)";
980   CompileSuccessfully(spirv.c_str());
981   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
982 }
983 
TEST_F(ValidateIdWithMessage,OpTypeRuntimeArrayGood)984 TEST_F(ValidateIdWithMessage, OpTypeRuntimeArrayGood) {
985   std::string spirv = kGLSL450MemoryModel + R"(
986 %1 = OpTypeInt 32 0
987 %2 = OpTypeRuntimeArray %1)";
988   CompileSuccessfully(spirv.c_str());
989   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
990 }
TEST_F(ValidateIdWithMessage,OpTypeRuntimeArrayBad)991 TEST_F(ValidateIdWithMessage, OpTypeRuntimeArrayBad) {
992   std::string spirv = kGLSL450MemoryModel + R"(
993 %1 = OpTypeInt 32 0
994 %2 = OpConstant %1 0
995 %3 = OpTypeRuntimeArray %2)";
996   CompileSuccessfully(spirv.c_str());
997   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
998   EXPECT_THAT(
999       getDiagnosticString(),
1000       HasSubstr("OpTypeRuntimeArray Element Type <id> '2[%uint_0]' is not a "
1001                 "type."));
1002 }
1003 // TODO: Object of this type can only be created with OpVariable using the
1004 // Unifrom Storage Class
1005 
TEST_F(ValidateIdWithMessage,OpTypeStructGood)1006 TEST_F(ValidateIdWithMessage, OpTypeStructGood) {
1007   std::string spirv = kGLSL450MemoryModel + R"(
1008 %1 = OpTypeInt 32 0
1009 %2 = OpTypeFloat 64
1010 %3 = OpTypePointer Input %1
1011 %4 = OpTypeStruct %1 %2 %3)";
1012   CompileSuccessfully(spirv.c_str());
1013   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1014 }
TEST_F(ValidateIdWithMessage,OpTypeStructMemberTypeBad)1015 TEST_F(ValidateIdWithMessage, OpTypeStructMemberTypeBad) {
1016   std::string spirv = kGLSL450MemoryModel + R"(
1017 %1 = OpTypeInt 32 0
1018 %2 = OpTypeFloat 64
1019 %3 = OpConstant %2 0.0
1020 %4 = OpTypeStruct %1 %2 %3)";
1021   CompileSuccessfully(spirv.c_str());
1022   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1023   EXPECT_THAT(getDiagnosticString(),
1024               HasSubstr("OpTypeStruct Member Type <id> '3[%double_0]' is not "
1025                         "a type."));
1026 }
1027 
TEST_F(ValidateIdWithMessage,OpTypeStructOpaqueTypeBad)1028 TEST_F(ValidateIdWithMessage, OpTypeStructOpaqueTypeBad) {
1029   std::string spirv = R"(
1030                OpCapability Shader
1031                OpMemoryModel Logical GLSL450
1032                OpEntryPoint Vertex %main "main"
1033           %1 = OpTypeSampler
1034           %2 = OpTypeStruct %1
1035        %void = OpTypeVoid
1036           %3 = OpTypeFunction %void
1037        %main = OpFunction %void None %3
1038           %5 = OpLabel
1039                OpReturn
1040                OpFunctionEnd
1041 )";
1042   CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0);
1043   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1044   EXPECT_THAT(getDiagnosticString(),
1045               HasSubstr("OpTypeStruct must not contain an opaque type"));
1046 }
1047 
TEST_F(ValidateIdWithMessage,OpTypePointerGood)1048 TEST_F(ValidateIdWithMessage, OpTypePointerGood) {
1049   std::string spirv = kGLSL450MemoryModel + R"(
1050 %1 = OpTypeInt 32 0
1051 %2 = OpTypePointer Input %1)";
1052   CompileSuccessfully(spirv.c_str());
1053   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1054 }
TEST_F(ValidateIdWithMessage,OpTypePointerBad)1055 TEST_F(ValidateIdWithMessage, OpTypePointerBad) {
1056   std::string spirv = kGLSL450MemoryModel + R"(
1057 %1 = OpTypeInt 32 0
1058 %2 = OpConstant %1 0
1059 %3 = OpTypePointer Input %2)";
1060   CompileSuccessfully(spirv.c_str());
1061   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1062   EXPECT_THAT(getDiagnosticString(),
1063               HasSubstr("OpTypePointer Type <id> '2[%uint_0]' is not a "
1064                         "type."));
1065 }
1066 
TEST_F(ValidateIdWithMessage,OpTypeFunctionGood)1067 TEST_F(ValidateIdWithMessage, OpTypeFunctionGood) {
1068   std::string spirv = kGLSL450MemoryModel + R"(
1069 %1 = OpTypeVoid
1070 %2 = OpTypeFunction %1)";
1071   CompileSuccessfully(spirv.c_str());
1072   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1073 }
TEST_F(ValidateIdWithMessage,OpTypeFunctionReturnTypeBad)1074 TEST_F(ValidateIdWithMessage, OpTypeFunctionReturnTypeBad) {
1075   std::string spirv = kGLSL450MemoryModel + R"(
1076 %1 = OpTypeInt 32 0
1077 %2 = OpConstant %1 0
1078 %3 = OpTypeFunction %2)";
1079   CompileSuccessfully(spirv.c_str());
1080   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1081   EXPECT_THAT(getDiagnosticString(),
1082               HasSubstr("OpTypeFunction Return Type <id> '2[%uint_0]' is not "
1083                         "a type."));
1084 }
TEST_F(ValidateIdWithMessage,OpTypeFunctionParameterBad)1085 TEST_F(ValidateIdWithMessage, OpTypeFunctionParameterBad) {
1086   std::string spirv = kGLSL450MemoryModel + R"(
1087 %1 = OpTypeVoid
1088 %2 = OpTypeInt 32 0
1089 %3 = OpConstant %2 0
1090 %4 = OpTypeFunction %1 %2 %3)";
1091   CompileSuccessfully(spirv.c_str());
1092   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1093   EXPECT_THAT(
1094       getDiagnosticString(),
1095       HasSubstr("OpTypeFunction Parameter Type <id> '3[%uint_0]' is not a "
1096                 "type."));
1097 }
1098 
TEST_F(ValidateIdWithMessage,OpTypeFunctionParameterTypeVoidBad)1099 TEST_F(ValidateIdWithMessage, OpTypeFunctionParameterTypeVoidBad) {
1100   std::string spirv = kGLSL450MemoryModel + R"(
1101 %1 = OpTypeVoid
1102 %2 = OpTypeInt 32 0
1103 %4 = OpTypeFunction %1 %2 %1)";
1104   CompileSuccessfully(spirv.c_str());
1105   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1106   EXPECT_THAT(getDiagnosticString(),
1107               HasSubstr("OpTypeFunction Parameter Type <id> '1[%void]' cannot "
1108                         "be OpTypeVoid."));
1109 }
1110 
TEST_F(ValidateIdWithMessage,OpTypePipeGood)1111 TEST_F(ValidateIdWithMessage, OpTypePipeGood) {
1112   std::string spirv = kGLSL450MemoryModel + R"(
1113 %1 = OpTypeFloat 32
1114 %2 = OpTypeVector %1 16
1115 %3 = OpTypePipe ReadOnly)";
1116   CompileSuccessfully(spirv.c_str());
1117   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1118 }
1119 
TEST_F(ValidateIdWithMessage,OpConstantTrueGood)1120 TEST_F(ValidateIdWithMessage, OpConstantTrueGood) {
1121   std::string spirv = kGLSL450MemoryModel + R"(
1122 %1 = OpTypeBool
1123 %2 = OpConstantTrue %1)";
1124   CompileSuccessfully(spirv.c_str());
1125   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1126 }
TEST_F(ValidateIdWithMessage,OpConstantTrueBad)1127 TEST_F(ValidateIdWithMessage, OpConstantTrueBad) {
1128   std::string spirv = kGLSL450MemoryModel + R"(
1129 %1 = OpTypeVoid
1130 %2 = OpConstantTrue %1)";
1131   CompileSuccessfully(spirv.c_str());
1132   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1133   EXPECT_THAT(
1134       getDiagnosticString(),
1135       HasSubstr("OpConstantTrue Result Type <id> '1[%void]' is not a boolean "
1136                 "type."));
1137 }
1138 
TEST_F(ValidateIdWithMessage,OpConstantFalseGood)1139 TEST_F(ValidateIdWithMessage, OpConstantFalseGood) {
1140   std::string spirv = kGLSL450MemoryModel + R"(
1141 %1 = OpTypeBool
1142 %2 = OpConstantTrue %1)";
1143   CompileSuccessfully(spirv.c_str());
1144   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1145 }
TEST_F(ValidateIdWithMessage,OpConstantFalseBad)1146 TEST_F(ValidateIdWithMessage, OpConstantFalseBad) {
1147   std::string spirv = kGLSL450MemoryModel + R"(
1148 %1 = OpTypeVoid
1149 %2 = OpConstantFalse %1)";
1150   CompileSuccessfully(spirv.c_str());
1151   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1152   EXPECT_THAT(
1153       getDiagnosticString(),
1154       HasSubstr("OpConstantFalse Result Type <id> '1[%void]' is not a boolean "
1155                 "type."));
1156 }
1157 
TEST_F(ValidateIdWithMessage,OpConstantGood)1158 TEST_F(ValidateIdWithMessage, OpConstantGood) {
1159   std::string spirv = kGLSL450MemoryModel + R"(
1160 %1 = OpTypeInt 32 0
1161 %2 = OpConstant %1 1)";
1162   CompileSuccessfully(spirv.c_str());
1163   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1164 }
TEST_F(ValidateIdWithMessage,OpConstantBad)1165 TEST_F(ValidateIdWithMessage, OpConstantBad) {
1166   std::string spirv = kGLSL450MemoryModel + R"(
1167 %1 = OpTypeVoid
1168 %2 = OpConstant !1 !0)";
1169   // The expected failure code is implementation dependent (currently
1170   // INVALID_BINARY because the binary parser catches these cases) and may
1171   // change over time, but this must always fail.
1172   CompileSuccessfully(spirv.c_str());
1173   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
1174 }
1175 
TEST_F(ValidateIdWithMessage,OpConstantCompositeVectorGood)1176 TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorGood) {
1177   std::string spirv = kGLSL450MemoryModel + R"(
1178 %1 = OpTypeFloat 32
1179 %2 = OpTypeVector %1 4
1180 %3 = OpConstant %1 3.14
1181 %4 = OpConstantComposite %2 %3 %3 %3 %3)";
1182   CompileSuccessfully(spirv.c_str());
1183   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1184 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeVectorWithUndefGood)1185 TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorWithUndefGood) {
1186   std::string spirv = kGLSL450MemoryModel + R"(
1187 %1 = OpTypeFloat 32
1188 %2 = OpTypeVector %1 4
1189 %3 = OpConstant %1 3.14
1190 %9 = OpUndef %1
1191 %4 = OpConstantComposite %2 %3 %3 %3 %9)";
1192   CompileSuccessfully(spirv.c_str());
1193   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1194 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeVectorResultTypeBad)1195 TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorResultTypeBad) {
1196   std::string spirv = kGLSL450MemoryModel + R"(
1197 %1 = OpTypeFloat 32
1198 %2 = OpTypeVector %1 4
1199 %3 = OpConstant %1 3.14
1200 %4 = OpConstantComposite %1 %3 %3 %3 %3)";
1201   CompileSuccessfully(spirv.c_str());
1202   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1203   EXPECT_THAT(
1204       getDiagnosticString(),
1205       HasSubstr("OpConstantComposite Result Type <id> '1[%float]' is not a "
1206                 "composite type."));
1207 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeVectorConstituentTypeBad)1208 TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorConstituentTypeBad) {
1209   std::string spirv = kGLSL450MemoryModel + R"(
1210 %1 = OpTypeFloat 32
1211 %2 = OpTypeVector %1 4
1212 %4 = OpTypeInt 32 0
1213 %3 = OpConstant %1 3.14
1214 %5 = OpConstant %4 42 ; bad type for constant value
1215 %6 = OpConstantComposite %2 %3 %5 %3 %3)";
1216   CompileSuccessfully(spirv.c_str());
1217   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1218   EXPECT_THAT(
1219       getDiagnosticString(),
1220       HasSubstr("OpConstantComposite Constituent <id> '5[%uint_42]'s type "
1221                 "does not match Result Type <id> '2[%v4float]'s vector "
1222                 "element type."));
1223 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeVectorConstituentUndefTypeBad)1224 TEST_F(ValidateIdWithMessage,
1225        OpConstantCompositeVectorConstituentUndefTypeBad) {
1226   std::string spirv = kGLSL450MemoryModel + R"(
1227 %1 = OpTypeFloat 32
1228 %2 = OpTypeVector %1 4
1229 %4 = OpTypeInt 32 0
1230 %3 = OpConstant %1 3.14
1231 %5 = OpUndef %4 ; bad type for undef value
1232 %6 = OpConstantComposite %2 %3 %5 %3 %3)";
1233   CompileSuccessfully(spirv.c_str());
1234   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1235   EXPECT_THAT(
1236       getDiagnosticString(),
1237       HasSubstr("OpConstantComposite Constituent <id> '5[%5]'s type does not "
1238                 "match Result Type <id> '2[%v4float]'s vector element type."));
1239 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeMatrixGood)1240 TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixGood) {
1241   std::string spirv = kGLSL450MemoryModel + R"(
1242  %1 = OpTypeFloat 32
1243  %2 = OpTypeVector %1 4
1244  %3 = OpTypeMatrix %2 4
1245  %4 = OpConstant %1 1.0
1246  %5 = OpConstant %1 0.0
1247  %6 = OpConstantComposite %2 %4 %5 %5 %5
1248  %7 = OpConstantComposite %2 %5 %4 %5 %5
1249  %8 = OpConstantComposite %2 %5 %5 %4 %5
1250  %9 = OpConstantComposite %2 %5 %5 %5 %4
1251 %10 = OpConstantComposite %3 %6 %7 %8 %9)";
1252   CompileSuccessfully(spirv.c_str());
1253   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1254 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeMatrixUndefGood)1255 TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixUndefGood) {
1256   std::string spirv = kGLSL450MemoryModel + R"(
1257  %1 = OpTypeFloat 32
1258  %2 = OpTypeVector %1 4
1259  %3 = OpTypeMatrix %2 4
1260  %4 = OpConstant %1 1.0
1261  %5 = OpConstant %1 0.0
1262  %6 = OpConstantComposite %2 %4 %5 %5 %5
1263  %7 = OpConstantComposite %2 %5 %4 %5 %5
1264  %8 = OpConstantComposite %2 %5 %5 %4 %5
1265  %9 = OpUndef %2
1266 %10 = OpConstantComposite %3 %6 %7 %8 %9)";
1267   CompileSuccessfully(spirv.c_str());
1268   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1269 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeMatrixConstituentTypeBad)1270 TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixConstituentTypeBad) {
1271   std::string spirv = kGLSL450MemoryModel + R"(
1272  %1 = OpTypeFloat 32
1273  %2 = OpTypeVector %1 4
1274 %11 = OpTypeVector %1 3
1275  %3 = OpTypeMatrix %2 4
1276  %4 = OpConstant %1 1.0
1277  %5 = OpConstant %1 0.0
1278  %6 = OpConstantComposite %2 %4 %5 %5 %5
1279  %7 = OpConstantComposite %2 %5 %4 %5 %5
1280  %8 = OpConstantComposite %2 %5 %5 %4 %5
1281  %9 = OpConstantComposite %11 %5 %5 %5
1282 %10 = OpConstantComposite %3 %6 %7 %8 %9)";
1283   CompileSuccessfully(spirv.c_str());
1284   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1285   EXPECT_THAT(getDiagnosticString(),
1286               HasSubstr("OpConstantComposite Constituent <id> '10[%10]' vector "
1287                         "component count does not match Result Type <id> "
1288                         "'4[%mat4v4float]'s vector component count."));
1289 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeMatrixConstituentUndefTypeBad)1290 TEST_F(ValidateIdWithMessage,
1291        OpConstantCompositeMatrixConstituentUndefTypeBad) {
1292   std::string spirv = kGLSL450MemoryModel + R"(
1293  %1 = OpTypeFloat 32
1294  %2 = OpTypeVector %1 4
1295 %11 = OpTypeVector %1 3
1296  %3 = OpTypeMatrix %2 4
1297  %4 = OpConstant %1 1.0
1298  %5 = OpConstant %1 0.0
1299  %6 = OpConstantComposite %2 %4 %5 %5 %5
1300  %7 = OpConstantComposite %2 %5 %4 %5 %5
1301  %8 = OpConstantComposite %2 %5 %5 %4 %5
1302  %9 = OpUndef %11
1303 %10 = OpConstantComposite %3 %6 %7 %8 %9)";
1304   CompileSuccessfully(spirv.c_str());
1305   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1306   EXPECT_THAT(getDiagnosticString(),
1307               HasSubstr("OpConstantComposite Constituent <id> '10[%10]' vector "
1308                         "component count does not match Result Type <id> "
1309                         "'4[%mat4v4float]'s vector component count."));
1310 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayGood)1311 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayGood) {
1312   std::string spirv = kGLSL450MemoryModel + R"(
1313 %1 = OpTypeInt 32 0
1314 %2 = OpConstant %1 4
1315 %3 = OpTypeArray %1 %2
1316 %4 = OpConstantComposite %3 %2 %2 %2 %2)";
1317   CompileSuccessfully(spirv.c_str());
1318   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1319 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayWithUndefGood)1320 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayWithUndefGood) {
1321   std::string spirv = kGLSL450MemoryModel + R"(
1322 %1 = OpTypeInt 32 0
1323 %2 = OpConstant %1 4
1324 %9 = OpUndef %1
1325 %3 = OpTypeArray %1 %2
1326 %4 = OpConstantComposite %3 %2 %2 %2 %9)";
1327   CompileSuccessfully(spirv.c_str());
1328   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1329 }
1330 
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayConstConstituentTypeBad)1331 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstConstituentTypeBad) {
1332   std::string spirv = kGLSL450MemoryModel + R"(
1333 %1 = OpTypeInt 32 0
1334 %2 = OpConstant %1 4
1335 %3 = OpTypeArray %1 %2
1336 %4 = OpConstantComposite %3 %2 %2 %2 %1)";  // Uses a type as operand
1337   CompileSuccessfully(spirv.c_str());
1338   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1339   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%uint] cannot be a "
1340                                                "type"));
1341 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayConstConstituentBad)1342 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstConstituentBad) {
1343   std::string spirv = kGLSL450MemoryModel + R"(
1344 %1 = OpTypeInt 32 0
1345 %2 = OpConstant %1 4
1346 %3 = OpTypeArray %1 %2
1347 %4 = OpTypePointer Uniform %1
1348 %5 = OpVariable %4 Uniform
1349 %6 = OpConstantComposite %3 %2 %2 %2 %5)";
1350   CompileSuccessfully(spirv.c_str());
1351   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1352   EXPECT_THAT(getDiagnosticString(),
1353               HasSubstr("OpConstantComposite Constituent <id> '5[%5]' is not a "
1354                         "constant or undef."));
1355 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayConstituentTypeBad)1356 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentTypeBad) {
1357   std::string spirv = kGLSL450MemoryModel + R"(
1358 %1 = OpTypeInt 32 0
1359 %2 = OpConstant %1 4
1360 %3 = OpTypeArray %1 %2
1361 %5 = OpTypeFloat 32
1362 %6 = OpConstant %5 3.14 ; bad type for const value
1363 %4 = OpConstantComposite %3 %2 %2 %2 %6)";
1364   CompileSuccessfully(spirv.c_str());
1365   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1366   EXPECT_THAT(getDiagnosticString(),
1367               HasSubstr("OpConstantComposite Constituent <id> "
1368                         "'5[%float_3_1400001]'s type does not match Result "
1369                         "Type <id> '3[%_arr_uint_uint_4]'s array element "
1370                         "type."));
1371 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeArrayConstituentUndefTypeBad)1372 TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentUndefTypeBad) {
1373   std::string spirv = kGLSL450MemoryModel + R"(
1374 %1 = OpTypeInt 32 0
1375 %2 = OpConstant %1 4
1376 %3 = OpTypeArray %1 %2
1377 %5 = OpTypeFloat 32
1378 %6 = OpUndef %5 ; bad type for undef
1379 %4 = OpConstantComposite %3 %2 %2 %2 %6)";
1380   CompileSuccessfully(spirv.c_str());
1381   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1382   EXPECT_THAT(getDiagnosticString(),
1383               HasSubstr("OpConstantComposite Constituent <id> "
1384                         "'5[%5]'s type does not match Result "
1385                         "Type <id> '3[%_arr_uint_uint_4]'s array element "
1386                         "type."));
1387 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeStructGood)1388 TEST_F(ValidateIdWithMessage, OpConstantCompositeStructGood) {
1389   std::string spirv = kGLSL450MemoryModel + R"(
1390 %1 = OpTypeInt 32 0
1391 %2 = OpTypeInt 64 0
1392 %3 = OpTypeStruct %1 %1 %2
1393 %4 = OpConstant %1 42
1394 %5 = OpConstant %2 4300000000
1395 %6 = OpConstantComposite %3 %4 %4 %5)";
1396   CompileSuccessfully(spirv.c_str());
1397   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1398 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeStructUndefGood)1399 TEST_F(ValidateIdWithMessage, OpConstantCompositeStructUndefGood) {
1400   std::string spirv = kGLSL450MemoryModel + R"(
1401 %1 = OpTypeInt 32 0
1402 %2 = OpTypeInt 64 0
1403 %3 = OpTypeStruct %1 %1 %2
1404 %4 = OpConstant %1 42
1405 %5 = OpUndef %2
1406 %6 = OpConstantComposite %3 %4 %4 %5)";
1407   CompileSuccessfully(spirv.c_str());
1408   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1409 }
TEST_F(ValidateIdWithMessage,OpConstantCompositeStructMemberTypeBad)1410 TEST_F(ValidateIdWithMessage, OpConstantCompositeStructMemberTypeBad) {
1411   std::string spirv = kGLSL450MemoryModel + R"(
1412 %1 = OpTypeInt 32 0
1413 %2 = OpTypeInt 64 0
1414 %3 = OpTypeStruct %1 %1 %2
1415 %4 = OpConstant %1 42
1416 %5 = OpConstant %2 4300000000
1417 %6 = OpConstantComposite %3 %4 %5 %4)";
1418   CompileSuccessfully(spirv.c_str());
1419   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1420   EXPECT_THAT(getDiagnosticString(),
1421               HasSubstr("OpConstantComposite Constituent <id> "
1422                         "'5[%ulong_4300000000]' type does not match the "
1423                         "Result Type <id> '3[%_struct_3]'s member type."));
1424 }
1425 
TEST_F(ValidateIdWithMessage,OpConstantCompositeStructMemberUndefTypeBad)1426 TEST_F(ValidateIdWithMessage, OpConstantCompositeStructMemberUndefTypeBad) {
1427   std::string spirv = kGLSL450MemoryModel + R"(
1428 %1 = OpTypeInt 32 0
1429 %2 = OpTypeInt 64 0
1430 %3 = OpTypeStruct %1 %1 %2
1431 %4 = OpConstant %1 42
1432 %5 = OpUndef %2
1433 %6 = OpConstantComposite %3 %4 %5 %4)";
1434   CompileSuccessfully(spirv.c_str());
1435   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1436   EXPECT_THAT(getDiagnosticString(),
1437               HasSubstr("OpConstantComposite Constituent <id> '5[%5]' type "
1438                         "does not match the Result Type <id> '3[%_struct_3]'s "
1439                         "member type."));
1440 }
1441 
TEST_F(ValidateIdWithMessage,OpConstantSamplerGood)1442 TEST_F(ValidateIdWithMessage, OpConstantSamplerGood) {
1443   std::string spirv = kGLSL450MemoryModel + R"(
1444 %float = OpTypeFloat 32
1445 %samplerType = OpTypeSampler
1446 %3 = OpConstantSampler %samplerType ClampToEdge 0 Nearest)";
1447   CompileSuccessfully(spirv.c_str());
1448   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1449 }
TEST_F(ValidateIdWithMessage,OpConstantSamplerResultTypeBad)1450 TEST_F(ValidateIdWithMessage, OpConstantSamplerResultTypeBad) {
1451   std::string spirv = kGLSL450MemoryModel + R"(
1452 %1 = OpTypeFloat 32
1453 %2 = OpConstantSampler %1 Clamp 0 Nearest)";
1454   CompileSuccessfully(spirv.c_str());
1455   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1456   EXPECT_THAT(
1457       getDiagnosticString(),
1458       HasSubstr(
1459           "OpConstantSampler Result Type <id> '1[%float]' is not a sampler "
1460           "type."));
1461 }
1462 
TEST_F(ValidateIdWithMessage,OpConstantNullGood)1463 TEST_F(ValidateIdWithMessage, OpConstantNullGood) {
1464   std::string spirv = kGLSL450MemoryModel + R"(
1465  %1 = OpTypeBool
1466  %2 = OpConstantNull %1
1467  %3 = OpTypeInt 32 0
1468  %4 = OpConstantNull %3
1469  %5 = OpTypeFloat 32
1470  %6 = OpConstantNull %5
1471  %7 = OpTypePointer UniformConstant %3
1472  %8 = OpConstantNull %7
1473  %9 = OpTypeEvent
1474 %10 = OpConstantNull %9
1475 %11 = OpTypeDeviceEvent
1476 %12 = OpConstantNull %11
1477 %13 = OpTypeReserveId
1478 %14 = OpConstantNull %13
1479 %15 = OpTypeQueue
1480 %16 = OpConstantNull %15
1481 %17 = OpTypeVector %5 2
1482 %18 = OpConstantNull %17
1483 %19 = OpTypeMatrix %17 2
1484 %20 = OpConstantNull %19
1485 %25 = OpConstant %3 8
1486 %21 = OpTypeArray %3 %25
1487 %22 = OpConstantNull %21
1488 %23 = OpTypeStruct %3 %5 %1
1489 %24 = OpConstantNull %23
1490 %26 = OpTypeArray %17 %25
1491 %27 = OpConstantNull %26
1492 %28 = OpTypeStruct %7 %26 %26 %1
1493 %29 = OpConstantNull %28
1494 )";
1495   CompileSuccessfully(spirv.c_str());
1496   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1497 }
1498 
TEST_F(ValidateIdWithMessage,OpConstantNullBasicBad)1499 TEST_F(ValidateIdWithMessage, OpConstantNullBasicBad) {
1500   std::string spirv = kGLSL450MemoryModel + R"(
1501 %1 = OpTypeVoid
1502 %2 = OpConstantNull %1)";
1503   CompileSuccessfully(spirv.c_str());
1504   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1505   EXPECT_THAT(
1506       getDiagnosticString(),
1507       HasSubstr("OpConstantNull Result Type <id> '1[%void]' cannot have a null "
1508                 "value."));
1509 }
1510 
TEST_F(ValidateIdWithMessage,OpConstantNullArrayBad)1511 TEST_F(ValidateIdWithMessage, OpConstantNullArrayBad) {
1512   std::string spirv = kGLSL450MemoryModel + R"(
1513 %2 = OpTypeInt 32 0
1514 %3 = OpTypeSampler
1515 %4 = OpConstant %2 4
1516 %5 = OpTypeArray %3 %4
1517 %6 = OpConstantNull %5)";
1518   CompileSuccessfully(spirv.c_str());
1519   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1520   EXPECT_THAT(
1521       getDiagnosticString(),
1522       HasSubstr(
1523           "OpConstantNull Result Type <id> '4[%_arr_2_uint_4]' cannot have a "
1524           "null value."));
1525 }
1526 
TEST_F(ValidateIdWithMessage,OpConstantNullStructBad)1527 TEST_F(ValidateIdWithMessage, OpConstantNullStructBad) {
1528   std::string spirv = kGLSL450MemoryModel + R"(
1529 %2 = OpTypeSampler
1530 %3 = OpTypeStruct %2 %2
1531 %4 = OpConstantNull %3)";
1532   CompileSuccessfully(spirv.c_str());
1533   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1534   EXPECT_THAT(getDiagnosticString(),
1535               HasSubstr("OpConstantNull Result Type <id> '2[%_struct_2]' "
1536                         "cannot have a null value."));
1537 }
1538 
TEST_F(ValidateIdWithMessage,OpConstantNullRuntimeArrayBad)1539 TEST_F(ValidateIdWithMessage, OpConstantNullRuntimeArrayBad) {
1540   std::string spirv = kGLSL450MemoryModel + R"(
1541 %bool = OpTypeBool
1542 %array = OpTypeRuntimeArray %bool
1543 %null = OpConstantNull %array)";
1544   CompileSuccessfully(spirv.c_str());
1545   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1546   EXPECT_THAT(
1547       getDiagnosticString(),
1548       HasSubstr(
1549           "OpConstantNull Result Type <id> '2[%_runtimearr_bool]' cannot have "
1550           "a null value."));
1551 }
1552 
TEST_F(ValidateIdWithMessage,OpSpecConstantTrueGood)1553 TEST_F(ValidateIdWithMessage, OpSpecConstantTrueGood) {
1554   std::string spirv = kGLSL450MemoryModel + R"(
1555 %1 = OpTypeBool
1556 %2 = OpSpecConstantTrue %1)";
1557   CompileSuccessfully(spirv.c_str());
1558   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1559 }
TEST_F(ValidateIdWithMessage,OpSpecConstantTrueBad)1560 TEST_F(ValidateIdWithMessage, OpSpecConstantTrueBad) {
1561   std::string spirv = kGLSL450MemoryModel + R"(
1562 %1 = OpTypeVoid
1563 %2 = OpSpecConstantTrue %1)";
1564   CompileSuccessfully(spirv.c_str());
1565   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1566   EXPECT_THAT(getDiagnosticString(),
1567               HasSubstr("OpSpecConstantTrue Result Type <id> '1[%void]' is not "
1568                         "a boolean type"));
1569 }
1570 
TEST_F(ValidateIdWithMessage,OpSpecConstantFalseGood)1571 TEST_F(ValidateIdWithMessage, OpSpecConstantFalseGood) {
1572   std::string spirv = kGLSL450MemoryModel + R"(
1573 %1 = OpTypeBool
1574 %2 = OpSpecConstantFalse %1)";
1575   CompileSuccessfully(spirv.c_str());
1576   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1577 }
TEST_F(ValidateIdWithMessage,OpSpecConstantFalseBad)1578 TEST_F(ValidateIdWithMessage, OpSpecConstantFalseBad) {
1579   std::string spirv = kGLSL450MemoryModel + R"(
1580 %1 = OpTypeVoid
1581 %2 = OpSpecConstantFalse %1)";
1582   CompileSuccessfully(spirv.c_str());
1583   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1584   EXPECT_THAT(
1585       getDiagnosticString(),
1586       HasSubstr("OpSpecConstantFalse Result Type <id> '1[%void]' is not "
1587                 "a boolean type"));
1588 }
1589 
TEST_F(ValidateIdWithMessage,OpSpecConstantGood)1590 TEST_F(ValidateIdWithMessage, OpSpecConstantGood) {
1591   std::string spirv = kGLSL450MemoryModel + R"(
1592 %1 = OpTypeFloat 32
1593 %2 = OpSpecConstant %1 42)";
1594   CompileSuccessfully(spirv.c_str());
1595   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1596 }
TEST_F(ValidateIdWithMessage,OpSpecConstantBad)1597 TEST_F(ValidateIdWithMessage, OpSpecConstantBad) {
1598   std::string spirv = kGLSL450MemoryModel + R"(
1599 %1 = OpTypeVoid
1600 %2 = OpSpecConstant !1 !4)";
1601   // The expected failure code is implementation dependent (currently
1602   // INVALID_BINARY because the binary parser catches these cases) and may
1603   // change over time, but this must always fail.
1604   CompileSuccessfully(spirv.c_str());
1605   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
1606   EXPECT_THAT(getDiagnosticString(),
1607               HasSubstr("Type Id 1 is not a scalar numeric type"));
1608 }
1609 
1610 // Valid: SpecConstantComposite specializes to a vector.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorGood)1611 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorGood) {
1612   std::string spirv = kGLSL450MemoryModel + R"(
1613 %1 = OpTypeFloat 32
1614 %2 = OpTypeVector %1 4
1615 %3 = OpSpecConstant %1 3.14
1616 %4 = OpConstant %1 3.14
1617 %5 = OpSpecConstantComposite %2 %3 %3 %4 %4)";
1618   CompileSuccessfully(spirv.c_str());
1619   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1620 }
1621 
1622 // Valid: Vector of floats and Undefs.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorWithUndefGood)1623 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorWithUndefGood) {
1624   std::string spirv = kGLSL450MemoryModel + R"(
1625 %1 = OpTypeFloat 32
1626 %2 = OpTypeVector %1 4
1627 %3 = OpSpecConstant %1 3.14
1628 %5 = OpConstant %1 3.14
1629 %9 = OpUndef %1
1630 %4 = OpSpecConstantComposite %2 %3 %5 %3 %9)";
1631   CompileSuccessfully(spirv.c_str());
1632   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1633 }
1634 
1635 // Invalid: result type is float.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorResultTypeBad)1636 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorResultTypeBad) {
1637   std::string spirv = kGLSL450MemoryModel + R"(
1638 %1 = OpTypeFloat 32
1639 %2 = OpTypeVector %1 4
1640 %3 = OpSpecConstant %1 3.14
1641 %4 = OpSpecConstantComposite %1 %3 %3 %3 %3)";
1642   CompileSuccessfully(spirv.c_str());
1643   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1644   EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a composite type"));
1645 }
1646 
1647 // Invalid: Vector contains a mix of Int and Float.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorConstituentTypeBad)1648 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorConstituentTypeBad) {
1649   std::string spirv = kGLSL450MemoryModel + R"(
1650 %1 = OpTypeFloat 32
1651 %2 = OpTypeVector %1 4
1652 %4 = OpTypeInt 32 0
1653 %3 = OpSpecConstant %1 3.14
1654 %5 = OpConstant %4 42 ; bad type for constant value
1655 %6 = OpSpecConstantComposite %2 %3 %5 %3 %3)";
1656   CompileSuccessfully(spirv.c_str());
1657   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1658   EXPECT_THAT(getDiagnosticString(),
1659               HasSubstr("OpSpecConstantComposite Constituent <id> "
1660                         "'5[%uint_42]'s type does not match Result Type <id> "
1661                         "'2[%v4float]'s vector element type."));
1662 }
1663 
1664 // Invalid: Constituent is not a constant
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorConstituentNotConstantBad)1665 TEST_F(ValidateIdWithMessage,
1666        OpSpecConstantCompositeVectorConstituentNotConstantBad) {
1667   std::string spirv = kGLSL450MemoryModel + R"(
1668 %1 = OpTypeFloat 32
1669 %2 = OpTypeVector %1 4
1670 %3 = OpTypeInt 32 0
1671 %4 = OpSpecConstant %1 3.14
1672 %5 = OpTypePointer Uniform %1
1673 %6 = OpVariable %5 Uniform
1674 %7 = OpSpecConstantComposite %2 %6 %4 %4 %4)";
1675   CompileSuccessfully(spirv.c_str());
1676   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1677   EXPECT_THAT(getDiagnosticString(),
1678               HasSubstr("OpSpecConstantComposite Constituent <id> '6[%6]' is "
1679                         "not a constant or undef."));
1680 }
1681 
1682 // Invalid: Vector contains a mix of Undef-int and Float.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorConstituentUndefTypeBad)1683 TEST_F(ValidateIdWithMessage,
1684        OpSpecConstantCompositeVectorConstituentUndefTypeBad) {
1685   std::string spirv = kGLSL450MemoryModel + R"(
1686 %1 = OpTypeFloat 32
1687 %2 = OpTypeVector %1 4
1688 %4 = OpTypeInt 32 0
1689 %3 = OpSpecConstant %1 3.14
1690 %5 = OpUndef %4 ; bad type for undef value
1691 %6 = OpSpecConstantComposite %2 %3 %5 %3 %3)";
1692   CompileSuccessfully(spirv.c_str());
1693   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1694   EXPECT_THAT(getDiagnosticString(),
1695               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]'s "
1696                         "type does not match Result Type <id> '2[%v4float]'s "
1697                         "vector element type."));
1698 }
1699 
1700 // Invalid: Vector expects 3 components, but 4 specified.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeVectorNumComponentsBad)1701 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorNumComponentsBad) {
1702   std::string spirv = kGLSL450MemoryModel + R"(
1703 %1 = OpTypeFloat 32
1704 %2 = OpTypeVector %1 3
1705 %3 = OpConstant %1 3.14
1706 %5 = OpSpecConstant %1 4.0
1707 %6 = OpSpecConstantComposite %2 %3 %5 %3 %3)";
1708   CompileSuccessfully(spirv.c_str());
1709   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1710   EXPECT_THAT(getDiagnosticString(),
1711               HasSubstr("OpSpecConstantComposite Constituent <id> count does "
1712                         "not match Result Type <id> '2[%v3float]'s vector "
1713                         "component count."));
1714 }
1715 
1716 // Valid: 4x4 matrix of floats
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixGood)1717 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixGood) {
1718   std::string spirv = kGLSL450MemoryModel + R"(
1719  %1 = OpTypeFloat 32
1720  %2 = OpTypeVector %1 4
1721  %3 = OpTypeMatrix %2 4
1722  %4 = OpConstant %1 1.0
1723  %5 = OpSpecConstant %1 0.0
1724  %6 = OpSpecConstantComposite %2 %4 %5 %5 %5
1725  %7 = OpSpecConstantComposite %2 %5 %4 %5 %5
1726  %8 = OpSpecConstantComposite %2 %5 %5 %4 %5
1727  %9 = OpSpecConstantComposite %2 %5 %5 %5 %4
1728 %10 = OpSpecConstantComposite %3 %6 %7 %8 %9)";
1729   CompileSuccessfully(spirv.c_str());
1730   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1731 }
1732 
1733 // Valid: Matrix in which one column is Undef
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixUndefGood)1734 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixUndefGood) {
1735   std::string spirv = kGLSL450MemoryModel + R"(
1736  %1 = OpTypeFloat 32
1737  %2 = OpTypeVector %1 4
1738  %3 = OpTypeMatrix %2 4
1739  %4 = OpConstant %1 1.0
1740  %5 = OpSpecConstant %1 0.0
1741  %6 = OpSpecConstantComposite %2 %4 %5 %5 %5
1742  %7 = OpSpecConstantComposite %2 %5 %4 %5 %5
1743  %8 = OpSpecConstantComposite %2 %5 %5 %4 %5
1744  %9 = OpUndef %2
1745 %10 = OpSpecConstantComposite %3 %6 %7 %8 %9)";
1746   CompileSuccessfully(spirv.c_str());
1747   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1748 }
1749 
1750 // Invalid: Matrix in which the sizes of column vectors are not equal.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixConstituentTypeBad)1751 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixConstituentTypeBad) {
1752   std::string spirv = kGLSL450MemoryModel + R"(
1753  %1 = OpTypeFloat 32
1754  %2 = OpTypeVector %1 4
1755  %3 = OpTypeVector %1 3
1756  %4 = OpTypeMatrix %2 4
1757  %5 = OpSpecConstant %1 1.0
1758  %6 = OpConstant %1 0.0
1759  %7 = OpSpecConstantComposite %2 %5 %6 %6 %6
1760  %8 = OpSpecConstantComposite %2 %6 %5 %6 %6
1761  %9 = OpSpecConstantComposite %2 %6 %6 %5 %6
1762  %10 = OpSpecConstantComposite %3 %6 %6 %6
1763 %11 = OpSpecConstantComposite %4 %7 %8 %9 %10)";
1764   CompileSuccessfully(spirv.c_str());
1765   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1766   EXPECT_THAT(getDiagnosticString(),
1767               HasSubstr("OpSpecConstantComposite Constituent <id> '10[%10]' "
1768                         "vector component count does not match Result Type "
1769                         "<id> '4[%mat4v4float]'s vector component count."));
1770 }
1771 
1772 // Invalid: Matrix type expects 4 columns but only 3 specified.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixNumColsBad)1773 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixNumColsBad) {
1774   std::string spirv = kGLSL450MemoryModel + R"(
1775  %1 = OpTypeFloat 32
1776  %2 = OpTypeVector %1 4
1777  %3 = OpTypeMatrix %2 4
1778  %4 = OpSpecConstant %1 1.0
1779  %5 = OpConstant %1 0.0
1780  %6 = OpSpecConstantComposite %2 %4 %5 %5 %5
1781  %7 = OpSpecConstantComposite %2 %5 %4 %5 %5
1782  %8 = OpSpecConstantComposite %2 %5 %5 %4 %5
1783 %10 = OpSpecConstantComposite %3 %6 %7 %8)";
1784   CompileSuccessfully(spirv.c_str());
1785   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1786   EXPECT_THAT(
1787       getDiagnosticString(),
1788       HasSubstr("OpSpecConstantComposite Constituent <id> count does "
1789                 "not match Result Type <id> '3[%mat4v4float]'s matrix column "
1790                 "count."));
1791 }
1792 
1793 // Invalid: Composite contains a non-const/undef component
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixConstituentNotConstBad)1794 TEST_F(ValidateIdWithMessage,
1795        OpSpecConstantCompositeMatrixConstituentNotConstBad) {
1796   std::string spirv = kGLSL450MemoryModel + R"(
1797  %1 = OpTypeFloat 32
1798  %2 = OpConstant %1 0.0
1799  %3 = OpTypeVector %1 4
1800  %4 = OpTypeMatrix %3 4
1801  %5 = OpSpecConstantComposite %3 %2 %2 %2 %2
1802  %6 = OpTypePointer Uniform %1
1803  %7 = OpVariable %6 Uniform
1804  %8 = OpSpecConstantComposite %4 %5 %5 %5 %7)";
1805   CompileSuccessfully(spirv.c_str());
1806   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1807   EXPECT_THAT(getDiagnosticString(),
1808               HasSubstr("OpSpecConstantComposite Constituent <id> '7[%7]' is "
1809                         "not a constant or undef."));
1810 }
1811 
1812 // Invalid: Composite contains a column that is *not* a vector (it's an array)
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixColTypeBad)1813 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixColTypeBad) {
1814   std::string spirv = kGLSL450MemoryModel + R"(
1815  %1 = OpTypeFloat 32
1816  %2 = OpTypeInt 32 0
1817  %3 = OpSpecConstant %2 4
1818  %4 = OpConstant %1 0.0
1819  %5 = OpTypeVector %1 4
1820  %6 = OpTypeArray %2 %3
1821  %7 = OpTypeMatrix %5 4
1822  %8  = OpSpecConstantComposite %6 %3 %3 %3 %3
1823  %9  = OpSpecConstantComposite %5 %4 %4 %4 %4
1824  %10 = OpSpecConstantComposite %7 %9 %9 %9 %8)";
1825   CompileSuccessfully(spirv.c_str());
1826   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1827   EXPECT_THAT(getDiagnosticString(),
1828               HasSubstr("OpSpecConstantComposite Constituent <id> '8[%8]' type "
1829                         "does not match Result Type <id> '7[%mat4v4float]'s "
1830                         "matrix column type."));
1831 }
1832 
1833 // Invalid: Matrix with an Undef column of the wrong size.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixConstituentUndefTypeBad)1834 TEST_F(ValidateIdWithMessage,
1835        OpSpecConstantCompositeMatrixConstituentUndefTypeBad) {
1836   std::string spirv = kGLSL450MemoryModel + R"(
1837  %1 = OpTypeFloat 32
1838  %2 = OpTypeVector %1 4
1839  %3 = OpTypeVector %1 3
1840  %4 = OpTypeMatrix %2 4
1841  %5 = OpSpecConstant %1 1.0
1842  %6 = OpSpecConstant %1 0.0
1843  %7 = OpSpecConstantComposite %2 %5 %6 %6 %6
1844  %8 = OpSpecConstantComposite %2 %6 %5 %6 %6
1845  %9 = OpSpecConstantComposite %2 %6 %6 %5 %6
1846  %10 = OpUndef %3
1847  %11 = OpSpecConstantComposite %4 %7 %8 %9 %10)";
1848   CompileSuccessfully(spirv.c_str());
1849   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1850   EXPECT_THAT(getDiagnosticString(),
1851               HasSubstr("OpSpecConstantComposite Constituent <id> '10[%10]' "
1852                         "vector component count does not match Result Type "
1853                         "<id> '4[%mat4v4float]'s vector component count."));
1854 }
1855 
1856 // Invalid: Matrix in which some columns are Int and some are Float.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeMatrixColumnTypeBad)1857 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixColumnTypeBad) {
1858   std::string spirv = kGLSL450MemoryModel + R"(
1859  %1 = OpTypeInt 32 0
1860  %2 = OpTypeFloat 32
1861  %3 = OpTypeVector %1 2
1862  %4 = OpTypeVector %2 2
1863  %5 = OpTypeMatrix %4 2
1864  %6 = OpSpecConstant %1 42
1865  %7 = OpConstant %2 3.14
1866  %8 = OpSpecConstantComposite %3 %6 %6
1867  %9 = OpSpecConstantComposite %4 %7 %7
1868 %10 = OpSpecConstantComposite %5 %8 %9)";
1869   CompileSuccessfully(spirv.c_str());
1870   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1871   EXPECT_THAT(getDiagnosticString(),
1872               HasSubstr("OpSpecConstantComposite Constituent <id> '8[%8]' "
1873                         "component type does not match Result Type <id> "
1874                         "'5[%mat2v2float]'s matrix column component type."));
1875 }
1876 
1877 // Valid: Array of integers
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayGood)1878 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayGood) {
1879   std::string spirv = kGLSL450MemoryModel + R"(
1880 %1 = OpTypeInt 32 0
1881 %2 = OpSpecConstant %1 4
1882 %5 = OpConstant %1 5
1883 %3 = OpTypeArray %1 %2
1884 %6 = OpTypeArray %1 %5
1885 %4 = OpSpecConstantComposite %3 %2 %2 %2 %2
1886 %7 = OpSpecConstantComposite %3 %5 %5 %5 %5)";
1887   CompileSuccessfully(spirv.c_str());
1888   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1889 }
1890 
1891 // Invalid: Expecting an array of 4 components, but 3 specified.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayNumComponentsBad)1892 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayNumComponentsBad) {
1893   std::string spirv = kGLSL450MemoryModel + R"(
1894 %1 = OpTypeInt 32 0
1895 %2 = OpConstant %1 4
1896 %3 = OpTypeArray %1 %2
1897 %4 = OpSpecConstantComposite %3 %2 %2 %2)";
1898   CompileSuccessfully(spirv.c_str());
1899   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1900   EXPECT_THAT(getDiagnosticString(),
1901               HasSubstr("OpSpecConstantComposite Constituent count does not "
1902                         "match Result Type <id> '3[%_arr_uint_uint_4]'s array "
1903                         "length."));
1904 }
1905 
1906 // Valid: Array of Integers and Undef-int
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayWithUndefGood)1907 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayWithUndefGood) {
1908   std::string spirv = kGLSL450MemoryModel + R"(
1909 %1 = OpTypeInt 32 0
1910 %2 = OpSpecConstant %1 4
1911 %9 = OpUndef %1
1912 %3 = OpTypeArray %1 %2
1913 %4 = OpSpecConstantComposite %3 %2 %2 %2 %9)";
1914   CompileSuccessfully(spirv.c_str());
1915   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1916 }
1917 
1918 // Invalid: Array uses a type as operand.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayConstConstituentBad)1919 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayConstConstituentBad) {
1920   std::string spirv = kGLSL450MemoryModel + R"(
1921 %1 = OpTypeInt 32 0
1922 %2 = OpConstant %1 4
1923 %3 = OpTypeArray %1 %2
1924 %4 = OpTypePointer Uniform %1
1925 %5 = OpVariable %4 Uniform
1926 %6 = OpSpecConstantComposite %3 %2 %2 %2 %5)";
1927   CompileSuccessfully(spirv.c_str());
1928   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1929   EXPECT_THAT(getDiagnosticString(),
1930               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]' is "
1931                         "not a constant or undef."));
1932 }
1933 
1934 // Invalid: Array has a mix of Int and Float components.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayConstituentTypeBad)1935 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayConstituentTypeBad) {
1936   std::string spirv = kGLSL450MemoryModel + R"(
1937 %1 = OpTypeInt 32 0
1938 %2 = OpConstant %1 4
1939 %3 = OpTypeArray %1 %2
1940 %4 = OpTypeFloat 32
1941 %5 = OpSpecConstant %4 3.14 ; bad type for const value
1942 %6 = OpSpecConstantComposite %3 %2 %2 %2 %5)";
1943   CompileSuccessfully(spirv.c_str());
1944   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1945   EXPECT_THAT(getDiagnosticString(),
1946               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]'s "
1947                         "type does not match Result Type <id> "
1948                         "'3[%_arr_uint_uint_4]'s array element type."));
1949 }
1950 
1951 // Invalid: Array has a mix of Int and Undef-float.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeArrayConstituentUndefTypeBad)1952 TEST_F(ValidateIdWithMessage,
1953        OpSpecConstantCompositeArrayConstituentUndefTypeBad) {
1954   std::string spirv = kGLSL450MemoryModel + R"(
1955 %1 = OpTypeInt 32 0
1956 %2 = OpSpecConstant %1 4
1957 %3 = OpTypeArray %1 %2
1958 %5 = OpTypeFloat 32
1959 %6 = OpUndef %5 ; bad type for undef
1960 %4 = OpSpecConstantComposite %3 %2 %2 %2 %6)";
1961   CompileSuccessfully(spirv.c_str());
1962   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1963   EXPECT_THAT(getDiagnosticString(),
1964               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]'s "
1965                         "type does not match Result Type <id> "
1966                         "'3[%_arr_uint_2]'s array element type."));
1967 }
1968 
1969 // Valid: Struct of {Int32,Int32,Int64}.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructGood)1970 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructGood) {
1971   std::string spirv = kGLSL450MemoryModel + R"(
1972 %1 = OpTypeInt 32 0
1973 %2 = OpTypeInt 64 0
1974 %3 = OpTypeStruct %1 %1 %2
1975 %4 = OpConstant %1 42
1976 %5 = OpSpecConstant %2 4300000000
1977 %6 = OpSpecConstantComposite %3 %4 %4 %5)";
1978   CompileSuccessfully(spirv.c_str());
1979   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1980 }
1981 
1982 // Invalid: missing one int32 struct member.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructMissingComponentBad)1983 TEST_F(ValidateIdWithMessage,
1984        OpSpecConstantCompositeStructMissingComponentBad) {
1985   std::string spirv = kGLSL450MemoryModel + R"(
1986 %1 = OpTypeInt 32 0
1987 %3 = OpTypeStruct %1 %1 %1
1988 %4 = OpConstant %1 42
1989 %5 = OpSpecConstant %1 430
1990 %6 = OpSpecConstantComposite %3 %4 %5)";
1991   CompileSuccessfully(spirv.c_str());
1992   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1993   EXPECT_THAT(getDiagnosticString(),
1994               HasSubstr("OpSpecConstantComposite Constituent <id> "
1995                         "'2[%_struct_2]' count does not match Result Type "
1996                         "<id> '2[%_struct_2]'s struct member count."));
1997 }
1998 
1999 // Valid: Struct uses Undef-int64.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructUndefGood)2000 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructUndefGood) {
2001   std::string spirv = kGLSL450MemoryModel + R"(
2002 %1 = OpTypeInt 32 0
2003 %2 = OpTypeInt 64 0
2004 %3 = OpTypeStruct %1 %1 %2
2005 %4 = OpSpecConstant %1 42
2006 %5 = OpUndef %2
2007 %6 = OpSpecConstantComposite %3 %4 %4 %5)";
2008   CompileSuccessfully(spirv.c_str());
2009   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2010 }
2011 
2012 // Invalid: Composite contains non-const/undef component.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructNonConstBad)2013 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructNonConstBad) {
2014   std::string spirv = kGLSL450MemoryModel + R"(
2015 %1 = OpTypeInt 32 0
2016 %2 = OpTypeInt 64 0
2017 %3 = OpTypeStruct %1 %1 %2
2018 %4 = OpSpecConstant %1 42
2019 %5 = OpUndef %2
2020 %6 = OpTypePointer Uniform %1
2021 %7 = OpVariable %6 Uniform
2022 %8 = OpSpecConstantComposite %3 %4 %7 %5)";
2023   CompileSuccessfully(spirv.c_str());
2024   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2025   EXPECT_THAT(getDiagnosticString(),
2026               HasSubstr("OpSpecConstantComposite Constituent <id> '7[%7]' is "
2027                         "not a constant or undef."));
2028 }
2029 
2030 // Invalid: Struct component type does not match expected specialization type.
2031 // Second component was expected to be Int32, but got Int64.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructMemberTypeBad)2032 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructMemberTypeBad) {
2033   std::string spirv = kGLSL450MemoryModel + R"(
2034 %1 = OpTypeInt 32 0
2035 %2 = OpTypeInt 64 0
2036 %3 = OpTypeStruct %1 %1 %2
2037 %4 = OpConstant %1 42
2038 %5 = OpSpecConstant %2 4300000000
2039 %6 = OpSpecConstantComposite %3 %4 %5 %4)";
2040   CompileSuccessfully(spirv.c_str());
2041   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2042   EXPECT_THAT(getDiagnosticString(),
2043               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]' type "
2044                         "does not match the Result Type <id> '3[%_struct_3]'s "
2045                         "member type."));
2046 }
2047 
2048 // Invalid: Undef-int64 used when Int32 was expected.
TEST_F(ValidateIdWithMessage,OpSpecConstantCompositeStructMemberUndefTypeBad)2049 TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructMemberUndefTypeBad) {
2050   std::string spirv = kGLSL450MemoryModel + R"(
2051 %1 = OpTypeInt 32 0
2052 %2 = OpTypeInt 64 0
2053 %3 = OpTypeStruct %1 %1 %2
2054 %4 = OpSpecConstant %1 42
2055 %5 = OpUndef %2
2056 %6 = OpSpecConstantComposite %3 %4 %5 %4)";
2057   CompileSuccessfully(spirv.c_str());
2058   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2059   EXPECT_THAT(getDiagnosticString(),
2060               HasSubstr("OpSpecConstantComposite Constituent <id> '5[%5]' type "
2061                         "does not match the Result Type <id> '3[%_struct_3]'s "
2062                         "member type."));
2063 }
2064 
2065 // TODO: OpSpecConstantOp
2066 
TEST_F(ValidateIdWithMessage,OpVariableGood)2067 TEST_F(ValidateIdWithMessage, OpVariableGood) {
2068   std::string spirv = kGLSL450MemoryModel + R"(
2069 %1 = OpTypeInt 32 0
2070 %2 = OpTypePointer Input %1
2071 %3 = OpVariable %2 Input)";
2072   CompileSuccessfully(spirv.c_str());
2073   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2074 }
TEST_F(ValidateIdWithMessage,OpVariableInitializerConstantGood)2075 TEST_F(ValidateIdWithMessage, OpVariableInitializerConstantGood) {
2076   std::string spirv = kGLSL450MemoryModel + R"(
2077 %1 = OpTypeInt 32 0
2078 %2 = OpTypePointer Input %1
2079 %3 = OpConstant %1 42
2080 %4 = OpVariable %2 Input %3)";
2081   CompileSuccessfully(spirv.c_str());
2082   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2083 }
TEST_F(ValidateIdWithMessage,OpVariableInitializerGlobalVariableGood)2084 TEST_F(ValidateIdWithMessage, OpVariableInitializerGlobalVariableGood) {
2085   std::string spirv = kGLSL450MemoryModel + R"(
2086 %1 = OpTypeInt 32 0
2087 %2 = OpTypePointer Uniform %1
2088 %3 = OpVariable %2 Uniform
2089 %4 = OpTypePointer Private %2 ; pointer to pointer
2090 %5 = OpVariable %4 Private %3
2091 )";
2092   CompileSuccessfully(spirv.c_str());
2093   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2094 }
2095 // TODO: Positive test OpVariable with OpConstantNull of OpTypePointer
TEST_F(ValidateIdWithMessage,OpVariableResultTypeBad)2096 TEST_F(ValidateIdWithMessage, OpVariableResultTypeBad) {
2097   std::string spirv = kGLSL450MemoryModel + R"(
2098 %1 = OpTypeInt 32 0
2099 %2 = OpVariable %1 Input)";
2100   CompileSuccessfully(spirv.c_str());
2101   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2102   EXPECT_THAT(
2103       getDiagnosticString(),
2104       HasSubstr("OpVariable Result Type <id> '1[%uint]' is not a pointer "
2105                 "type."));
2106 }
TEST_F(ValidateIdWithMessage,OpVariableInitializerIsTypeBad)2107 TEST_F(ValidateIdWithMessage, OpVariableInitializerIsTypeBad) {
2108   std::string spirv = kGLSL450MemoryModel + R"(
2109 %1 = OpTypeInt 32 0
2110 %2 = OpTypePointer Input %1
2111 %3 = OpVariable %2 Input %2)";
2112   CompileSuccessfully(spirv.c_str());
2113   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2114   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 2[%_ptr_Input_uint] "
2115                                                "cannot be a type"));
2116 }
2117 
TEST_F(ValidateIdWithMessage,OpVariableInitializerIsFunctionVarBad)2118 TEST_F(ValidateIdWithMessage, OpVariableInitializerIsFunctionVarBad) {
2119   std::string spirv = kGLSL450MemoryModel + R"(
2120 %int = OpTypeInt 32 0
2121 %ptrint = OpTypePointer Function %int
2122 %ptrptrint = OpTypePointer Function %ptrint
2123 %void = OpTypeVoid
2124 %fnty = OpTypeFunction %void
2125 %main = OpFunction %void None %fnty
2126 %entry = OpLabel
2127 %var = OpVariable %ptrint Function
2128 %varinit = OpVariable %ptrptrint Function %var ; Can't initialize function variable.
2129 OpReturn
2130 OpFunctionEnd
2131 )";
2132   CompileSuccessfully(spirv.c_str());
2133   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2134   EXPECT_THAT(getDiagnosticString(),
2135               HasSubstr("OpVariable Initializer <id> '8[%8]' is not a constant "
2136                         "or module-scope variable"));
2137 }
2138 
TEST_F(ValidateIdWithMessage,OpVariableInitializerIsModuleVarGood)2139 TEST_F(ValidateIdWithMessage, OpVariableInitializerIsModuleVarGood) {
2140   std::string spirv = kGLSL450MemoryModel + R"(
2141 %int = OpTypeInt 32 0
2142 %ptrint = OpTypePointer Uniform %int
2143 %mvar = OpVariable %ptrint Uniform
2144 %ptrptrint = OpTypePointer Function %ptrint
2145 %void = OpTypeVoid
2146 %fnty = OpTypeFunction %void
2147 %main = OpFunction %void None %fnty
2148 %entry = OpLabel
2149 %goodvar = OpVariable %ptrptrint Function %mvar ; This is ok
2150 OpReturn
2151 OpFunctionEnd
2152 )";
2153   CompileSuccessfully(spirv.c_str());
2154   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2155 }
2156 
TEST_F(ValidateIdWithMessage,OpVariableContainsBoolBad)2157 TEST_F(ValidateIdWithMessage, OpVariableContainsBoolBad) {
2158   std::string spirv = kGLSL450MemoryModel + R"(
2159 %bool = OpTypeBool
2160 %int = OpTypeInt 32 0
2161 %block = OpTypeStruct %bool %int
2162 %_ptr_Uniform_block = OpTypePointer Uniform %block
2163 %var = OpVariable %_ptr_Uniform_block Uniform
2164 %void = OpTypeVoid
2165 %fnty = OpTypeFunction %void
2166 %main = OpFunction %void None %fnty
2167 %entry = OpLabel
2168 %load = OpLoad %block %var
2169 OpReturn
2170 OpFunctionEnd
2171 )";
2172   CompileSuccessfully(spirv.c_str());
2173   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2174   EXPECT_THAT(getDiagnosticString(),
2175               HasSubstr("If OpTypeBool is stored in conjunction with OpVariable"
2176                         ", it can only be used with non-externally visible "
2177                         "shader Storage Classes: Workgroup, CrossWorkgroup, "
2178                         "Private, and Function"));
2179 }
2180 
TEST_F(ValidateIdWithMessage,OpVariableContainsBoolPointerGood)2181 TEST_F(ValidateIdWithMessage, OpVariableContainsBoolPointerGood) {
2182   std::string spirv = kGLSL450MemoryModel + R"(
2183 %bool = OpTypeBool
2184 %boolptr = OpTypePointer Uniform %bool
2185 %int = OpTypeInt 32 0
2186 %block = OpTypeStruct %boolptr %int
2187 %_ptr_Uniform_block = OpTypePointer Uniform %block
2188 %var = OpVariable %_ptr_Uniform_block Uniform
2189 %void = OpTypeVoid
2190 %fnty = OpTypeFunction %void
2191 %main = OpFunction %void None %fnty
2192 %entry = OpLabel
2193 %load = OpLoad %block %var
2194 OpReturn
2195 OpFunctionEnd
2196 )";
2197   CompileSuccessfully(spirv.c_str());
2198   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2199 }
2200 
TEST_F(ValidateIdWithMessage,OpVariableContainsBuiltinBoolGood)2201 TEST_F(ValidateIdWithMessage, OpVariableContainsBuiltinBoolGood) {
2202   std::string spirv = kGLSL450MemoryModel + R"(
2203 OpMemberDecorate %input 0 BuiltIn FrontFacing
2204 %bool = OpTypeBool
2205 %input = OpTypeStruct %bool
2206 %_ptr_input = OpTypePointer Input %input
2207 %var = OpVariable %_ptr_input Input
2208 %void = OpTypeVoid
2209 %fnty = OpTypeFunction %void
2210 %main = OpFunction %void None %fnty
2211 %entry = OpLabel
2212 %load = OpLoad %input %var
2213 OpReturn
2214 OpFunctionEnd
2215 )";
2216   CompileSuccessfully(spirv.c_str());
2217   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2218 }
2219 
TEST_F(ValidateIdWithMessage,OpVariableContainsRayPayloadBoolGood)2220 TEST_F(ValidateIdWithMessage, OpVariableContainsRayPayloadBoolGood) {
2221   std::string spirv = R"(
2222 OpCapability RayTracingNV
2223 OpCapability Shader
2224 OpCapability Linkage
2225 OpExtension "SPV_NV_ray_tracing"
2226 OpMemoryModel Logical GLSL450
2227 %bool = OpTypeBool
2228 %PerRayData = OpTypeStruct %bool
2229 %_ptr_PerRayData = OpTypePointer RayPayloadNV %PerRayData
2230 %var = OpVariable %_ptr_PerRayData RayPayloadNV
2231 %void = OpTypeVoid
2232 %fnty = OpTypeFunction %void
2233 %main = OpFunction %void None %fnty
2234 %entry = OpLabel
2235 %load = OpLoad %PerRayData %var
2236 OpReturn
2237 OpFunctionEnd
2238 )";
2239   CompileSuccessfully(spirv.c_str());
2240   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2241 }
2242 
TEST_F(ValidateIdWithMessage,OpVariablePointerNoVariablePointersBad)2243 TEST_F(ValidateIdWithMessage, OpVariablePointerNoVariablePointersBad) {
2244   const std::string spirv = R"(
2245 OpCapability Shader
2246 OpCapability Linkage
2247 OpMemoryModel Logical GLSL450
2248 %void = OpTypeVoid
2249 %int = OpTypeInt 32 0
2250 %_ptr_workgroup_int = OpTypePointer Workgroup %int
2251 %_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int
2252 %voidfn = OpTypeFunction %void
2253 %func = OpFunction %void None %voidfn
2254 %entry = OpLabel
2255 %var = OpVariable %_ptr_function_ptr Function
2256 OpReturn
2257 OpFunctionEnd
2258 )";
2259 
2260   CompileSuccessfully(spirv);
2261   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2262   EXPECT_THAT(
2263       getDiagnosticString(),
2264       HasSubstr(
2265           "In Logical addressing, variables may not allocate a pointer type"));
2266 }
2267 
TEST_F(ValidateIdWithMessage,OpVariablePointerNoVariablePointersRelaxedLogicalGood)2268 TEST_F(ValidateIdWithMessage,
2269        OpVariablePointerNoVariablePointersRelaxedLogicalGood) {
2270   const std::string spirv = R"(
2271 OpCapability Shader
2272 OpCapability Linkage
2273 OpMemoryModel Logical GLSL450
2274 %void = OpTypeVoid
2275 %int = OpTypeInt 32 0
2276 %_ptr_workgroup_int = OpTypePointer Workgroup %int
2277 %_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int
2278 %voidfn = OpTypeFunction %void
2279 %func = OpFunction %void None %voidfn
2280 %entry = OpLabel
2281 %var = OpVariable %_ptr_function_ptr Function
2282 OpReturn
2283 OpFunctionEnd
2284 )";
2285 
2286   auto options = getValidatorOptions();
2287   options->relax_logical_pointer = true;
2288   CompileSuccessfully(spirv);
2289   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2290 }
2291 
TEST_F(ValidateIdWithMessage,OpFunctionWithNonMemoryObject)2292 TEST_F(ValidateIdWithMessage, OpFunctionWithNonMemoryObject) {
2293   // DXC generates code that looks like when given something like:
2294   //   T t;
2295   //   t.s.fn_1();
2296   // This needs to be accepted before legalization takes place, so we
2297   // will include it with the relaxed logical pointer.
2298 
2299   const std::string spirv = R"(
2300                OpCapability Shader
2301                OpMemoryModel Logical GLSL450
2302                OpEntryPoint Vertex %1 "main"
2303                OpSource HLSL 600
2304         %int = OpTypeInt 32 1
2305       %int_0 = OpConstant %int 0
2306        %void = OpTypeVoid
2307           %9 = OpTypeFunction %void
2308   %_struct_5 = OpTypeStruct
2309   %_struct_6 = OpTypeStruct %_struct_5
2310 %_ptr_Function__struct_6 = OpTypePointer Function %_struct_6
2311 %_ptr_Function__struct_5 = OpTypePointer Function %_struct_5
2312          %23 = OpTypeFunction %void %_ptr_Function__struct_5
2313           %1 = OpFunction %void None %9
2314          %10 = OpLabel
2315          %11 = OpVariable %_ptr_Function__struct_6 Function
2316          %20 = OpAccessChain %_ptr_Function__struct_5 %11 %int_0
2317          %21 = OpFunctionCall %void %12 %20
2318                OpReturn
2319                OpFunctionEnd
2320          %12 = OpFunction %void None %23
2321          %13 = OpFunctionParameter %_ptr_Function__struct_5
2322          %14 = OpLabel
2323                OpReturn
2324                OpFunctionEnd
2325 )";
2326 
2327   auto options = getValidatorOptions();
2328   options->relax_logical_pointer = true;
2329   CompileSuccessfully(spirv);
2330   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2331 }
2332 
TEST_F(ValidateIdWithMessage,OpVariablePointerVariablePointersStorageBufferGood)2333 TEST_F(ValidateIdWithMessage,
2334        OpVariablePointerVariablePointersStorageBufferGood) {
2335   const std::string spirv = R"(
2336 OpCapability Shader
2337 OpCapability Linkage
2338 OpCapability VariablePointersStorageBuffer
2339 OpExtension "SPV_KHR_variable_pointers"
2340 OpMemoryModel Logical GLSL450
2341 %void = OpTypeVoid
2342 %int = OpTypeInt 32 0
2343 %_ptr_workgroup_int = OpTypePointer Workgroup %int
2344 %_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int
2345 %voidfn = OpTypeFunction %void
2346 %func = OpFunction %void None %voidfn
2347 %entry = OpLabel
2348 %var = OpVariable %_ptr_function_ptr Function
2349 OpReturn
2350 OpFunctionEnd
2351 )";
2352 
2353   CompileSuccessfully(spirv);
2354   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2355 }
2356 
TEST_F(ValidateIdWithMessage,OpVariablePointerVariablePointersGood)2357 TEST_F(ValidateIdWithMessage, OpVariablePointerVariablePointersGood) {
2358   const std::string spirv = R"(
2359 OpCapability Shader
2360 OpCapability Linkage
2361 OpCapability VariablePointers
2362 OpExtension "SPV_KHR_variable_pointers"
2363 OpMemoryModel Logical GLSL450
2364 %void = OpTypeVoid
2365 %int = OpTypeInt 32 0
2366 %_ptr_workgroup_int = OpTypePointer Workgroup %int
2367 %_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int
2368 %voidfn = OpTypeFunction %void
2369 %func = OpFunction %void None %voidfn
2370 %entry = OpLabel
2371 %var = OpVariable %_ptr_function_ptr Function
2372 OpReturn
2373 OpFunctionEnd
2374 )";
2375 
2376   CompileSuccessfully(spirv);
2377   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2378 }
2379 
TEST_F(ValidateIdWithMessage,OpVariablePointerVariablePointersBad)2380 TEST_F(ValidateIdWithMessage, OpVariablePointerVariablePointersBad) {
2381   const std::string spirv = R"(
2382 OpCapability Shader
2383 OpCapability VariablePointers
2384 OpExtension "SPV_KHR_variable_pointers"
2385 OpMemoryModel Logical GLSL450
2386 %void = OpTypeVoid
2387 %int = OpTypeInt 32 0
2388 %_ptr_workgroup_int = OpTypePointer Workgroup %int
2389 %_ptr_uniform_ptr = OpTypePointer Uniform %_ptr_workgroup_int
2390 %var = OpVariable %_ptr_uniform_ptr Uniform
2391 )";
2392 
2393   CompileSuccessfully(spirv);
2394   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2395   EXPECT_THAT(getDiagnosticString(),
2396               HasSubstr("In Logical addressing with variable pointers, "
2397                         "variables that allocate pointers must be in Function "
2398                         "or Private storage classes"));
2399 }
2400 
TEST_F(ValidateIdWithMessage,OpLoadGood)2401 TEST_F(ValidateIdWithMessage, OpLoadGood) {
2402   std::string spirv = kGLSL450MemoryModel + R"(
2403  %1 = OpTypeVoid
2404  %2 = OpTypeInt 32 0
2405  %3 = OpTypePointer UniformConstant %2
2406  %4 = OpTypeFunction %1
2407  %5 = OpVariable %3 UniformConstant
2408  %6 = OpFunction %1 None %4
2409  %7 = OpLabel
2410  %8 = OpLoad %2 %5
2411       OpReturn
2412       OpFunctionEnd
2413 )";
2414   CompileSuccessfully(spirv.c_str());
2415   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2416 }
2417 
2418 // TODO: Add tests that exercise VariablePointersStorageBuffer instead of
2419 // VariablePointers.
createVariablePointerSpirvProgram(std::ostringstream * spirv,std::string result_strategy,bool use_varptr_cap,bool add_helper_function)2420 void createVariablePointerSpirvProgram(std::ostringstream* spirv,
2421                                        std::string result_strategy,
2422                                        bool use_varptr_cap,
2423                                        bool add_helper_function) {
2424   *spirv << "OpCapability Shader ";
2425   if (use_varptr_cap) {
2426     *spirv << "OpCapability VariablePointers ";
2427     *spirv << "OpExtension \"SPV_KHR_variable_pointers\" ";
2428   }
2429   *spirv << "OpExtension \"SPV_KHR_storage_buffer_storage_class\" ";
2430   *spirv << R"(
2431     OpMemoryModel Logical GLSL450
2432     OpEntryPoint GLCompute %main "main"
2433     %void      = OpTypeVoid
2434     %voidf     = OpTypeFunction %void
2435     %bool      = OpTypeBool
2436     %i32       = OpTypeInt 32 1
2437     %f32       = OpTypeFloat 32
2438     %f32ptr    = OpTypePointer StorageBuffer %f32
2439     %i         = OpConstant %i32 1
2440     %zero      = OpConstant %i32 0
2441     %float_1   = OpConstant %f32 1.0
2442     %ptr1      = OpVariable %f32ptr StorageBuffer
2443     %ptr2      = OpVariable %f32ptr StorageBuffer
2444   )";
2445   if (add_helper_function) {
2446     *spirv << R"(
2447       ; ////////////////////////////////////////////////////////////
2448       ;;;; Function that returns a pointer
2449       ; ////////////////////////////////////////////////////////////
2450       %selector_func_type  = OpTypeFunction %f32ptr %bool %f32ptr %f32ptr
2451       %choose_input_func   = OpFunction %f32ptr None %selector_func_type
2452       %is_neg_param        = OpFunctionParameter %bool
2453       %first_ptr_param     = OpFunctionParameter %f32ptr
2454       %second_ptr_param    = OpFunctionParameter %f32ptr
2455       %selector_func_begin = OpLabel
2456       %result_ptr          = OpSelect %f32ptr %is_neg_param %first_ptr_param %second_ptr_param
2457       OpReturnValue %result_ptr
2458       OpFunctionEnd
2459     )";
2460   }
2461   *spirv << R"(
2462     %main      = OpFunction %void None %voidf
2463     %label     = OpLabel
2464   )";
2465   *spirv << result_strategy;
2466   *spirv << R"(
2467     OpReturn
2468     OpFunctionEnd
2469   )";
2470 }
2471 
2472 // With the VariablePointer Capability, OpLoad should allow loading a
2473 // VaiablePointer. In this test the variable pointer is obtained by an OpSelect
TEST_F(ValidateIdWithMessage,OpLoadVarPtrOpSelectGood)2474 TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpSelectGood) {
2475   std::string result_strategy = R"(
2476     %isneg     = OpSLessThan %bool %i %zero
2477     %varptr    = OpSelect %f32ptr %isneg %ptr1 %ptr2
2478     %result    = OpLoad %f32 %varptr
2479   )";
2480 
2481   std::ostringstream spirv;
2482   createVariablePointerSpirvProgram(&spirv, result_strategy,
2483                                     true /* Add VariablePointers Capability? */,
2484                                     false /* Use Helper Function? */);
2485   CompileSuccessfully(spirv.str());
2486   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2487 }
2488 
2489 // Without the VariablePointers Capability, OpLoad will not allow loading
2490 // through a variable pointer.
2491 // Disabled since using OpSelect with pointers without VariablePointers will
2492 // fail LogicalsPass.
TEST_F(ValidateIdWithMessage,DISABLED_OpLoadVarPtrOpSelectBad)2493 TEST_F(ValidateIdWithMessage, DISABLED_OpLoadVarPtrOpSelectBad) {
2494   std::string result_strategy = R"(
2495     %isneg     = OpSLessThan %bool %i %zero
2496     %varptr    = OpSelect %f32ptr %isneg %ptr1 %ptr2
2497     %result    = OpLoad %f32 %varptr
2498   )";
2499 
2500   std::ostringstream spirv;
2501   createVariablePointerSpirvProgram(&spirv, result_strategy,
2502                                     false /* Add VariablePointers Capability?*/,
2503                                     false /* Use Helper Function? */);
2504   CompileSuccessfully(spirv.str());
2505   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2506   EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a logical pointer."));
2507 }
2508 
2509 // With the VariablePointer Capability, OpLoad should allow loading a
2510 // VaiablePointer. In this test the variable pointer is obtained by an OpPhi
TEST_F(ValidateIdWithMessage,OpLoadVarPtrOpPhiGood)2511 TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpPhiGood) {
2512   std::string result_strategy = R"(
2513     %is_neg      = OpSLessThan %bool %i %zero
2514     OpSelectionMerge %end_label None
2515     OpBranchConditional %is_neg %take_ptr_1 %take_ptr_2
2516     %take_ptr_1 = OpLabel
2517     OpBranch      %end_label
2518     %take_ptr_2 = OpLabel
2519     OpBranch      %end_label
2520     %end_label  = OpLabel
2521     %varptr     = OpPhi %f32ptr %ptr1 %take_ptr_1 %ptr2 %take_ptr_2
2522     %result     = OpLoad %f32 %varptr
2523   )";
2524 
2525   std::ostringstream spirv;
2526   createVariablePointerSpirvProgram(&spirv, result_strategy,
2527                                     true /* Add VariablePointers Capability?*/,
2528                                     false /* Use Helper Function? */);
2529   CompileSuccessfully(spirv.str());
2530   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2531 }
2532 
2533 // Without the VariablePointers Capability, OpPhi can have a pointer result
2534 // type.
TEST_F(ValidateIdWithMessage,OpPhiBad)2535 TEST_F(ValidateIdWithMessage, OpPhiBad) {
2536   std::string result_strategy = R"(
2537     %is_neg      = OpSLessThan %bool %i %zero
2538     OpSelectionMerge %end_label None
2539     OpBranchConditional %is_neg %take_ptr_1 %take_ptr_2
2540     %take_ptr_1 = OpLabel
2541     OpBranch      %end_label
2542     %take_ptr_2 = OpLabel
2543     OpBranch      %end_label
2544     %end_label  = OpLabel
2545     %varptr     = OpPhi %f32ptr %ptr1 %take_ptr_1 %ptr2 %take_ptr_2
2546     %result     = OpLoad %f32 %varptr
2547   )";
2548 
2549   std::ostringstream spirv;
2550   createVariablePointerSpirvProgram(&spirv, result_strategy,
2551                                     false /* Add VariablePointers Capability?*/,
2552                                     false /* Use Helper Function? */);
2553   CompileSuccessfully(spirv.str());
2554   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
2555   EXPECT_THAT(getDiagnosticString(),
2556               HasSubstr("Using pointers with OpPhi requires capability "
2557                         "VariablePointers or VariablePointersStorageBuffer"));
2558 }
2559 
2560 // With the VariablePointer Capability, OpLoad should allow loading through a
2561 // VaiablePointer. In this test the variable pointer is obtained from an
2562 // OpFunctionCall (return value from a function)
TEST_F(ValidateIdWithMessage,OpLoadVarPtrOpFunctionCallGood)2563 TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpFunctionCallGood) {
2564   std::ostringstream spirv;
2565   std::string result_strategy = R"(
2566     %isneg     = OpSLessThan %bool %i %zero
2567     %varptr    = OpFunctionCall %f32ptr %choose_input_func %isneg %ptr1 %ptr2
2568     %result    = OpLoad %f32 %varptr
2569   )";
2570 
2571   createVariablePointerSpirvProgram(&spirv, result_strategy,
2572                                     true /* Add VariablePointers Capability?*/,
2573                                     true /* Use Helper Function? */);
2574   CompileSuccessfully(spirv.str());
2575   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2576 }
2577 
TEST_F(ValidateIdWithMessage,OpLoadResultTypeBad)2578 TEST_F(ValidateIdWithMessage, OpLoadResultTypeBad) {
2579   std::string spirv = kGLSL450MemoryModel + R"(
2580 %1 = OpTypeVoid
2581 %2 = OpTypeInt 32 0
2582 %3 = OpTypePointer UniformConstant %2
2583 %4 = OpTypeFunction %1
2584 %5 = OpVariable %3 UniformConstant
2585 %6 = OpFunction %1 None %4
2586 %7 = OpLabel
2587 %8 = OpLoad %3 %5
2588      OpReturn
2589      OpFunctionEnd
2590 )";
2591   CompileSuccessfully(spirv.c_str());
2592   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2593   EXPECT_THAT(getDiagnosticString(),
2594               HasSubstr("OpLoad Result Type <id> "
2595                         "'3[%_ptr_UniformConstant_uint]' does not match "
2596                         "Pointer <id> '5[%5]'s type."));
2597 }
2598 
TEST_F(ValidateIdWithMessage,OpLoadPointerBad)2599 TEST_F(ValidateIdWithMessage, OpLoadPointerBad) {
2600   std::string spirv = kGLSL450MemoryModel + R"(
2601 %1 = OpTypeVoid
2602 %2 = OpTypeInt 32 0
2603 %3 = OpTypePointer UniformConstant %2
2604 %4 = OpTypeFunction %1
2605 %5 = OpFunction %1 None %4
2606 %6 = OpLabel
2607 %7 = OpLoad %2 %8
2608      OpReturn
2609      OpFunctionEnd
2610 )";
2611   CompileSuccessfully(spirv.c_str());
2612   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2613   // Prove that SSA checks trigger for a bad Id value.
2614   // The next test case show the not-a-logical-pointer case.
2615   EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 8[%8] has not been "
2616                                                "defined"));
2617 }
2618 
2619 // Disabled as bitcasting type to object is now not valid.
TEST_F(ValidateIdWithMessage,DISABLED_OpLoadLogicalPointerBad)2620 TEST_F(ValidateIdWithMessage, DISABLED_OpLoadLogicalPointerBad) {
2621   std::string spirv = kGLSL450MemoryModel + R"(
2622 %1 = OpTypeVoid
2623 %2 = OpTypeInt 32 0
2624 %3 = OpTypeFloat 32
2625 %4 = OpTypePointer UniformConstant %2
2626 %5 = OpTypePointer UniformConstant %3
2627 %6 = OpTypeFunction %1
2628 %7 = OpFunction %1 None %6
2629 %8 = OpLabel
2630 %9 = OpBitcast %5 %4 ; Not valid in logical addressing
2631 %10 = OpLoad %3 %9 ; Should trigger message
2632      OpReturn
2633      OpFunctionEnd
2634 )";
2635   CompileSuccessfully(spirv.c_str());
2636   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2637   // Once we start checking bitcasts, we might catch that
2638   // as the error first, instead of catching it here.
2639   // I don't know if it's possible to generate a bad case
2640   // if/when the validator is complete.
2641   EXPECT_THAT(getDiagnosticString(),
2642               HasSubstr("OpLoad Pointer <id> '9' is not a logical pointer."));
2643 }
2644 
TEST_F(ValidateIdWithMessage,OpStoreGood)2645 TEST_F(ValidateIdWithMessage, OpStoreGood) {
2646   std::string spirv = kGLSL450MemoryModel + R"(
2647 %1 = OpTypeVoid
2648 %2 = OpTypeInt 32 0
2649 %3 = OpTypePointer Uniform %2
2650 %4 = OpTypeFunction %1
2651 %5 = OpConstant %2 42
2652 %6 = OpVariable %3 Uniform
2653 %7 = OpFunction %1 None %4
2654 %8 = OpLabel
2655      OpStore %6 %5
2656      OpReturn
2657      OpFunctionEnd)";
2658   CompileSuccessfully(spirv.c_str());
2659   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2660 }
TEST_F(ValidateIdWithMessage,OpStorePointerBad)2661 TEST_F(ValidateIdWithMessage, OpStorePointerBad) {
2662   std::string spirv = kGLSL450MemoryModel + R"(
2663 %1 = OpTypeVoid
2664 %2 = OpTypeInt 32 0
2665 %3 = OpTypePointer UniformConstant %2
2666 %4 = OpTypeFunction %1
2667 %5 = OpConstant %2 42
2668 %6 = OpVariable %3 UniformConstant
2669 %7 = OpConstant %2 0
2670 %8 = OpFunction %1 None %4
2671 %9 = OpLabel
2672      OpStore %7 %5
2673      OpReturn
2674      OpFunctionEnd)";
2675   CompileSuccessfully(spirv.c_str());
2676   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2677   EXPECT_THAT(getDiagnosticString(),
2678               HasSubstr("OpStore Pointer <id> '7[%uint_0]' is not a logical "
2679                         "pointer."));
2680 }
2681 
2682 // Disabled as bitcasting type to object is now not valid.
TEST_F(ValidateIdWithMessage,DISABLED_OpStoreLogicalPointerBad)2683 TEST_F(ValidateIdWithMessage, DISABLED_OpStoreLogicalPointerBad) {
2684   std::string spirv = kGLSL450MemoryModel + R"(
2685 %1 = OpTypeVoid
2686 %2 = OpTypeInt 32 0
2687 %3 = OpTypeFloat 32
2688 %4 = OpTypePointer UniformConstant %2
2689 %5 = OpTypePointer UniformConstant %3
2690 %6 = OpTypeFunction %1
2691 %7 = OpConstantNull %5
2692 %8 = OpFunction %1 None %6
2693 %9 = OpLabel
2694 %10 = OpBitcast %5 %4 ; Not valid in logical addressing
2695 %11 = OpStore %10 %7 ; Should trigger message
2696      OpReturn
2697      OpFunctionEnd
2698 )";
2699   CompileSuccessfully(spirv.c_str());
2700   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2701   EXPECT_THAT(getDiagnosticString(),
2702               HasSubstr("OpStore Pointer <id> '10' is not a logical pointer."));
2703 }
2704 
2705 // Without the VariablePointer Capability, OpStore should may not store
2706 // through a variable pointer.
2707 // Disabled since using OpSelect with pointers without VariablePointers will
2708 // fail LogicalsPass.
TEST_F(ValidateIdWithMessage,DISABLED_OpStoreVarPtrBad)2709 TEST_F(ValidateIdWithMessage, DISABLED_OpStoreVarPtrBad) {
2710   std::string result_strategy = R"(
2711     %isneg     = OpSLessThan %bool %i %zero
2712     %varptr    = OpSelect %f32ptr %isneg %ptr1 %ptr2
2713                  OpStore %varptr %float_1
2714   )";
2715 
2716   std::ostringstream spirv;
2717   createVariablePointerSpirvProgram(
2718       &spirv, result_strategy, false /* Add VariablePointers Capability? */,
2719       false /* Use Helper Function? */);
2720   CompileSuccessfully(spirv.str());
2721   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2722   EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a logical pointer."));
2723 }
2724 
2725 // With the VariablePointer Capability, OpStore should allow storing through a
2726 // variable pointer.
TEST_F(ValidateIdWithMessage,OpStoreVarPtrGood)2727 TEST_F(ValidateIdWithMessage, OpStoreVarPtrGood) {
2728   std::string result_strategy = R"(
2729     %isneg     = OpSLessThan %bool %i %zero
2730     %varptr    = OpSelect %f32ptr %isneg %ptr1 %ptr2
2731                  OpStore %varptr %float_1
2732   )";
2733 
2734   std::ostringstream spirv;
2735   createVariablePointerSpirvProgram(&spirv, result_strategy,
2736                                     true /* Add VariablePointers Capability? */,
2737                                     false /* Use Helper Function? */);
2738   CompileSuccessfully(spirv.str());
2739   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2740 }
2741 
TEST_F(ValidateIdWithMessage,OpStoreObjectGood)2742 TEST_F(ValidateIdWithMessage, OpStoreObjectGood) {
2743   std::string spirv = kGLSL450MemoryModel + R"(
2744 %1 = OpTypeVoid
2745 %2 = OpTypeInt 32 0
2746 %3 = OpTypePointer Uniform %2
2747 %4 = OpTypeFunction %1
2748 %5 = OpConstant %2 42
2749 %6 = OpVariable %3 Uniform
2750 %7 = OpFunction %1 None %4
2751 %8 = OpLabel
2752 %9 = OpUndef %1
2753      OpStore %6 %9
2754      OpReturn
2755      OpFunctionEnd)";
2756   CompileSuccessfully(spirv.c_str());
2757   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2758   EXPECT_THAT(getDiagnosticString(),
2759               HasSubstr("OpStore Object <id> '9[%9]'s type is void."));
2760 }
TEST_F(ValidateIdWithMessage,OpStoreTypeBad)2761 TEST_F(ValidateIdWithMessage, OpStoreTypeBad) {
2762   std::string spirv = kGLSL450MemoryModel + R"(
2763 %1 = OpTypeVoid
2764 %2 = OpTypeInt 32 0
2765 %9 = OpTypeFloat 32
2766 %3 = OpTypePointer Uniform %2
2767 %4 = OpTypeFunction %1
2768 %5 = OpConstant %9 3.14
2769 %6 = OpVariable %3 Uniform
2770 %7 = OpFunction %1 None %4
2771 %8 = OpLabel
2772      OpStore %6 %5
2773      OpReturn
2774      OpFunctionEnd)";
2775   CompileSuccessfully(spirv.c_str());
2776   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2777   EXPECT_THAT(getDiagnosticString(),
2778               HasSubstr("OpStore Pointer <id> '7[%7]'s type does not match "
2779                         "Object <id> '6[%float_3_1400001]'s type."));
2780 }
2781 
2782 // The next series of test check test a relaxation of the rules for stores to
2783 // structs.  The first test checks that we get a failure when the option is not
2784 // set to relax the rule.
2785 // TODO: Add tests for layout compatible arrays and matricies when the validator
2786 //       relaxes the rules for them as well.  Also need test to check for layout
2787 //       decorations specific to those types.
TEST_F(ValidateIdWithMessage,OpStoreTypeBadStruct)2788 TEST_F(ValidateIdWithMessage, OpStoreTypeBadStruct) {
2789   std::string spirv = kGLSL450MemoryModel + R"(
2790      OpMemberDecorate %1 0 Offset 0
2791      OpMemberDecorate %1 1 Offset 4
2792      OpMemberDecorate %2 0 Offset 0
2793      OpMemberDecorate %2 1 Offset 4
2794 %3 = OpTypeVoid
2795 %4 = OpTypeFloat 32
2796 %1 = OpTypeStruct %4 %4
2797 %5 = OpTypePointer Uniform %1
2798 %2 = OpTypeStruct %4 %4
2799 %6 = OpTypeFunction %3
2800 %7 = OpConstant %4 3.14
2801 %8 = OpVariable %5 Uniform
2802 %9 = OpFunction %3 None %6
2803 %10 = OpLabel
2804 %11 = OpCompositeConstruct %2 %7 %7
2805       OpStore %8 %11
2806       OpReturn
2807       OpFunctionEnd)";
2808   CompileSuccessfully(spirv.c_str());
2809   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2810   EXPECT_THAT(getDiagnosticString(),
2811               HasSubstr("OpStore Pointer <id> '8[%8]'s type does not match "
2812                         "Object <id> '11[%11]'s type."));
2813 }
2814 
2815 // Same code as the last test.  The difference is that we relax the rule.
2816 // Because the structs %3 and %5 are defined the same way.
TEST_F(ValidateIdWithMessage,OpStoreTypeRelaxedStruct)2817 TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedStruct) {
2818   std::string spirv = kGLSL450MemoryModel + R"(
2819      OpMemberDecorate %1 0 Offset 0
2820      OpMemberDecorate %1 1 Offset 4
2821      OpMemberDecorate %2 0 Offset 0
2822      OpMemberDecorate %2 1 Offset 4
2823 %3 = OpTypeVoid
2824 %4 = OpTypeFloat 32
2825 %1 = OpTypeStruct %4 %4
2826 %5 = OpTypePointer Uniform %1
2827 %2 = OpTypeStruct %4 %4
2828 %6 = OpTypeFunction %3
2829 %7 = OpConstant %4 3.14
2830 %8 = OpVariable %5 Uniform
2831 %9 = OpFunction %3 None %6
2832 %10 = OpLabel
2833 %11 = OpCompositeConstruct %2 %7 %7
2834       OpStore %8 %11
2835       OpReturn
2836       OpFunctionEnd)";
2837   spvValidatorOptionsSetRelaxStoreStruct(options_, true);
2838   CompileSuccessfully(spirv.c_str());
2839   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2840 }
2841 
2842 // Same code as the last test excect for an extra decoration on one of the
2843 // members. With the relaxed rules, the code is still valid.
TEST_F(ValidateIdWithMessage,OpStoreTypeRelaxedStructWithExtraDecoration)2844 TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedStructWithExtraDecoration) {
2845   std::string spirv = kGLSL450MemoryModel + R"(
2846      OpMemberDecorate %1 0 Offset 0
2847      OpMemberDecorate %1 1 Offset 4
2848      OpMemberDecorate %1 0 RelaxedPrecision
2849      OpMemberDecorate %2 0 Offset 0
2850      OpMemberDecorate %2 1 Offset 4
2851 %3 = OpTypeVoid
2852 %4 = OpTypeFloat 32
2853 %1 = OpTypeStruct %4 %4
2854 %5 = OpTypePointer Uniform %1
2855 %2 = OpTypeStruct %4 %4
2856 %6 = OpTypeFunction %3
2857 %7 = OpConstant %4 3.14
2858 %8 = OpVariable %5 Uniform
2859 %9 = OpFunction %3 None %6
2860 %10 = OpLabel
2861 %11 = OpCompositeConstruct %2 %7 %7
2862       OpStore %8 %11
2863       OpReturn
2864       OpFunctionEnd)";
2865   spvValidatorOptionsSetRelaxStoreStruct(options_, true);
2866   CompileSuccessfully(spirv.c_str());
2867   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2868 }
2869 
2870 // This test check that we recursively traverse the struct to check if they are
2871 // interchangable.
TEST_F(ValidateIdWithMessage,OpStoreTypeRelaxedNestedStruct)2872 TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedNestedStruct) {
2873   std::string spirv = kGLSL450MemoryModel + R"(
2874      OpMemberDecorate %1 0 Offset 0
2875      OpMemberDecorate %1 1 Offset 4
2876      OpMemberDecorate %2 0 Offset 0
2877      OpMemberDecorate %2 1 Offset 8
2878      OpMemberDecorate %3 0 Offset 0
2879      OpMemberDecorate %3 1 Offset 4
2880      OpMemberDecorate %4 0 Offset 0
2881      OpMemberDecorate %4 1 Offset 8
2882 %5 = OpTypeVoid
2883 %6 = OpTypeInt 32 0
2884 %7 = OpTypeFloat 32
2885 %1 = OpTypeStruct %7 %6
2886 %2 = OpTypeStruct %1 %1
2887 %8 = OpTypePointer Uniform %2
2888 %3 = OpTypeStruct %7 %6
2889 %4 = OpTypeStruct %3 %3
2890 %9 = OpTypeFunction %5
2891 %10 = OpConstant %6 7
2892 %11 = OpConstant %7 3.14
2893 %12 = OpConstantComposite %3 %11 %10
2894 %13 = OpVariable %8 Uniform
2895 %14 = OpFunction %5 None %9
2896 %15 = OpLabel
2897 %16 = OpCompositeConstruct %4 %12 %12
2898       OpStore %13 %16
2899       OpReturn
2900       OpFunctionEnd)";
2901   spvValidatorOptionsSetRelaxStoreStruct(options_, true);
2902   CompileSuccessfully(spirv.c_str());
2903   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
2904 }
2905 
2906 // This test check that the even with the relaxed rules an error is identified
2907 // if the members of the struct are in a different order.
TEST_F(ValidateIdWithMessage,OpStoreTypeBadRelaxedStruct1)2908 TEST_F(ValidateIdWithMessage, OpStoreTypeBadRelaxedStruct1) {
2909   std::string spirv = kGLSL450MemoryModel + R"(
2910      OpMemberDecorate %1 0 Offset 0
2911      OpMemberDecorate %1 1 Offset 4
2912      OpMemberDecorate %2 0 Offset 0
2913      OpMemberDecorate %2 1 Offset 8
2914      OpMemberDecorate %3 0 Offset 0
2915      OpMemberDecorate %3 1 Offset 4
2916      OpMemberDecorate %4 0 Offset 0
2917      OpMemberDecorate %4 1 Offset 8
2918 %5 = OpTypeVoid
2919 %6 = OpTypeInt 32 0
2920 %7 = OpTypeFloat 32
2921 %1 = OpTypeStruct %6 %7
2922 %2 = OpTypeStruct %1 %1
2923 %8 = OpTypePointer Uniform %2
2924 %3 = OpTypeStruct %7 %6
2925 %4 = OpTypeStruct %3 %3
2926 %9 = OpTypeFunction %5
2927 %10 = OpConstant %6 7
2928 %11 = OpConstant %7 3.14
2929 %12 = OpConstantComposite %3 %11 %10
2930 %13 = OpVariable %8 Uniform
2931 %14 = OpFunction %5 None %9
2932 %15 = OpLabel
2933 %16 = OpCompositeConstruct %4 %12 %12
2934       OpStore %13 %16
2935       OpReturn
2936       OpFunctionEnd)";
2937   spvValidatorOptionsSetRelaxStoreStruct(options_, true);
2938   CompileSuccessfully(spirv.c_str());
2939   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2940   EXPECT_THAT(
2941       getDiagnosticString(),
2942       HasSubstr("OpStore Pointer <id> '13[%13]'s layout does not match Object "
2943                 "<id> '16[%16]'s layout."));
2944 }
2945 
2946 // This test check that the even with the relaxed rules an error is identified
2947 // if the members of the struct are at different offsets.
TEST_F(ValidateIdWithMessage,OpStoreTypeBadRelaxedStruct2)2948 TEST_F(ValidateIdWithMessage, OpStoreTypeBadRelaxedStruct2) {
2949   std::string spirv = kGLSL450MemoryModel + R"(
2950      OpMemberDecorate %1 0 Offset 4
2951      OpMemberDecorate %1 1 Offset 0
2952      OpMemberDecorate %2 0 Offset 0
2953      OpMemberDecorate %2 1 Offset 8
2954      OpMemberDecorate %3 0 Offset 0
2955      OpMemberDecorate %3 1 Offset 4
2956      OpMemberDecorate %4 0 Offset 0
2957      OpMemberDecorate %4 1 Offset 8
2958 %5 = OpTypeVoid
2959 %6 = OpTypeInt 32 0
2960 %7 = OpTypeFloat 32
2961 %1 = OpTypeStruct %7 %6
2962 %2 = OpTypeStruct %1 %1
2963 %8 = OpTypePointer Uniform %2
2964 %3 = OpTypeStruct %7 %6
2965 %4 = OpTypeStruct %3 %3
2966 %9 = OpTypeFunction %5
2967 %10 = OpConstant %6 7
2968 %11 = OpConstant %7 3.14
2969 %12 = OpConstantComposite %3 %11 %10
2970 %13 = OpVariable %8 Uniform
2971 %14 = OpFunction %5 None %9
2972 %15 = OpLabel
2973 %16 = OpCompositeConstruct %4 %12 %12
2974       OpStore %13 %16
2975       OpReturn
2976       OpFunctionEnd)";
2977   spvValidatorOptionsSetRelaxStoreStruct(options_, true);
2978   CompileSuccessfully(spirv.c_str());
2979   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
2980   EXPECT_THAT(
2981       getDiagnosticString(),
2982       HasSubstr("OpStore Pointer <id> '13[%13]'s layout does not match Object "
2983                 "<id> '16[%16]'s layout."));
2984 }
2985 
TEST_F(ValidateIdWithMessage,OpStoreTypeRelaxedLogicalPointerReturnPointer)2986 TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedLogicalPointerReturnPointer) {
2987   const std::string spirv = R"(
2988      OpCapability Shader
2989      OpCapability Linkage
2990      OpMemoryModel Logical GLSL450
2991 %1 = OpTypeInt 32 1
2992 %2 = OpTypePointer Function %1
2993 %3 = OpTypeFunction %2 %2
2994 %4 = OpFunction %2 None %3
2995 %5 = OpFunctionParameter %2
2996 %6 = OpLabel
2997      OpReturnValue %5
2998      OpFunctionEnd)";
2999 
3000   spvValidatorOptionsSetRelaxLogicalPointer(options_, true);
3001   CompileSuccessfully(spirv.c_str());
3002   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3003 }
3004 
TEST_F(ValidateIdWithMessage,OpStoreTypeRelaxedLogicalPointerAllocPointer)3005 TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedLogicalPointerAllocPointer) {
3006   const std::string spirv = R"(
3007       OpCapability Shader
3008       OpCapability Linkage
3009       OpMemoryModel Logical GLSL450
3010  %1 = OpTypeVoid
3011  %2 = OpTypeInt 32 1
3012  %3 = OpTypeFunction %1          ; void(void)
3013  %4 = OpTypePointer Uniform %2   ; int*
3014  %5 = OpTypePointer Private %4   ; int** (Private)
3015  %6 = OpTypePointer Function %4  ; int** (Function)
3016  %7 = OpVariable %5 Private
3017  %8 = OpFunction %1 None %3
3018  %9 = OpLabel
3019 %10 = OpVariable %6 Function
3020       OpReturn
3021       OpFunctionEnd)";
3022 
3023   spvValidatorOptionsSetRelaxLogicalPointer(options_, true);
3024   CompileSuccessfully(spirv.c_str());
3025   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3026 }
3027 
TEST_F(ValidateIdWithMessage,OpStoreVoid)3028 TEST_F(ValidateIdWithMessage, OpStoreVoid) {
3029   std::string spirv = kGLSL450MemoryModel + R"(
3030 %1 = OpTypeVoid
3031 %2 = OpTypeInt 32 0
3032 %3 = OpTypePointer Uniform %2
3033 %4 = OpTypeFunction %1
3034 %6 = OpVariable %3 Uniform
3035 %7 = OpFunction %1 None %4
3036 %8 = OpLabel
3037 %9 = OpFunctionCall %1 %7
3038      OpStore %6 %9
3039      OpReturn
3040      OpFunctionEnd)";
3041   CompileSuccessfully(spirv.c_str());
3042   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3043   EXPECT_THAT(getDiagnosticString(),
3044               HasSubstr("OpStore Object <id> '8[%8]'s type is void."));
3045 }
3046 
TEST_F(ValidateIdWithMessage,OpStoreLabel)3047 TEST_F(ValidateIdWithMessage, OpStoreLabel) {
3048   std::string spirv = kGLSL450MemoryModel + R"(
3049 %1 = OpTypeVoid
3050 %2 = OpTypeInt 32 0
3051 %3 = OpTypePointer Uniform %2
3052 %4 = OpTypeFunction %1
3053 %6 = OpVariable %3 Uniform
3054 %7 = OpFunction %1 None %4
3055 %8 = OpLabel
3056      OpStore %6 %8
3057      OpReturn
3058      OpFunctionEnd)";
3059   CompileSuccessfully(spirv.c_str());
3060   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3061   EXPECT_THAT(getDiagnosticString(),
3062               HasSubstr("Operand 7[%7] requires a type"));
3063 }
3064 
3065 // TODO: enable when this bug is fixed:
3066 // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=15404
TEST_F(ValidateIdWithMessage,DISABLED_OpStoreFunction)3067 TEST_F(ValidateIdWithMessage, DISABLED_OpStoreFunction) {
3068   std::string spirv = kGLSL450MemoryModel + R"(
3069 %2 = OpTypeInt 32 0
3070 %3 = OpTypePointer UniformConstant %2
3071 %4 = OpTypeFunction %2
3072 %5 = OpConstant %2 123
3073 %6 = OpVariable %3 UniformConstant
3074 %7 = OpFunction %2 None %4
3075 %8 = OpLabel
3076      OpStore %6 %7
3077      OpReturnValue %5
3078      OpFunctionEnd)";
3079   CompileSuccessfully(spirv.c_str());
3080   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3081 }
3082 
TEST_F(ValidateIdWithMessage,OpStoreBuiltin)3083 TEST_F(ValidateIdWithMessage, OpStoreBuiltin) {
3084   std::string spirv = R"(
3085                OpCapability Shader
3086           %1 = OpExtInstImport "GLSL.std.450"
3087                OpMemoryModel Logical GLSL450
3088                OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
3089                OpExecutionMode %main LocalSize 1 1 1
3090                OpSource GLSL 450
3091                OpName %main "main"
3092 
3093                OpName %gl_GlobalInvocationID "gl_GlobalInvocationID"
3094                OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
3095 
3096         %int = OpTypeInt 32 1
3097        %uint = OpTypeInt 32 0
3098      %v3uint = OpTypeVector %uint 3
3099 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
3100 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
3101 
3102        %zero = OpConstant %uint 0
3103  %v3uint_000 = OpConstantComposite %v3uint %zero %zero %zero
3104 
3105        %void = OpTypeVoid
3106    %voidfunc = OpTypeFunction %void
3107        %main = OpFunction %void None %voidfunc
3108       %lmain = OpLabel
3109 
3110                OpStore %gl_GlobalInvocationID %v3uint_000
3111 
3112                OpReturn
3113                OpFunctionEnd
3114   )";
3115 
3116   CompileSuccessfully(spirv.c_str());
3117   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3118   EXPECT_THAT(getDiagnosticString(), HasSubstr("storage class is read-only"));
3119 }
3120 
TEST_F(ValidateIdWithMessage,OpCopyMemoryGood)3121 TEST_F(ValidateIdWithMessage, OpCopyMemoryGood) {
3122   std::string spirv = kGLSL450MemoryModel + R"(
3123  %1 = OpTypeVoid
3124  %2 = OpTypeInt 32 0
3125  %3 = OpTypePointer UniformConstant %2
3126  %4 = OpConstant %2 42
3127  %5 = OpVariable %3 UniformConstant %4
3128  %6 = OpTypePointer Function %2
3129  %7 = OpTypeFunction %1
3130  %8 = OpFunction %1 None %7
3131  %9 = OpLabel
3132 %10 = OpVariable %6 Function
3133       OpCopyMemory %10 %5 None
3134       OpReturn
3135       OpFunctionEnd
3136 )";
3137   CompileSuccessfully(spirv.c_str());
3138   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3139 }
3140 
TEST_F(ValidateIdWithMessage,OpCopyMemoryNonPointerTarget)3141 TEST_F(ValidateIdWithMessage, OpCopyMemoryNonPointerTarget) {
3142   const std::string spirv = kGLSL450MemoryModel + R"(
3143 %1 = OpTypeVoid
3144 %2 = OpTypeInt 32 0
3145 %3 = OpTypePointer Uniform %2
3146 %4 = OpTypeFunction %1 %2 %3
3147 %5 = OpFunction %1 None %4
3148 %6 = OpFunctionParameter %2
3149 %7 = OpFunctionParameter %3
3150 %8 = OpLabel
3151 OpCopyMemory %6 %7
3152 OpReturn
3153 OpFunctionEnd
3154 )";
3155 
3156   CompileSuccessfully(spirv);
3157   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3158   EXPECT_THAT(getDiagnosticString(),
3159               HasSubstr("Target operand <id> '6[%6]' is not a pointer."));
3160 }
3161 
TEST_F(ValidateIdWithMessage,OpCopyMemoryNonPointerSource)3162 TEST_F(ValidateIdWithMessage, OpCopyMemoryNonPointerSource) {
3163   const std::string spirv = kGLSL450MemoryModel + R"(
3164 %1 = OpTypeVoid
3165 %2 = OpTypeInt 32 0
3166 %3 = OpTypePointer Uniform %2
3167 %4 = OpTypeFunction %1 %2 %3
3168 %5 = OpFunction %1 None %4
3169 %6 = OpFunctionParameter %2
3170 %7 = OpFunctionParameter %3
3171 %8 = OpLabel
3172 OpCopyMemory %7 %6
3173 OpReturn
3174 OpFunctionEnd
3175 )";
3176 
3177   CompileSuccessfully(spirv);
3178   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3179   EXPECT_THAT(getDiagnosticString(),
3180               HasSubstr("Source operand <id> '6[%6]' is not a pointer."));
3181 }
3182 
TEST_F(ValidateIdWithMessage,OpCopyMemoryBad)3183 TEST_F(ValidateIdWithMessage, OpCopyMemoryBad) {
3184   std::string spirv = kGLSL450MemoryModel + R"(
3185  %1 = OpTypeVoid
3186  %2 = OpTypeInt 32 0
3187  %3 = OpTypePointer UniformConstant %2
3188  %4 = OpConstant %2 42
3189  %5 = OpVariable %3 UniformConstant %4
3190 %11 = OpTypeFloat 32
3191  %6 = OpTypePointer Function %11
3192  %7 = OpTypeFunction %1
3193  %8 = OpFunction %1 None %7
3194  %9 = OpLabel
3195 %10 = OpVariable %6 Function
3196       OpCopyMemory %10 %5 None
3197       OpReturn
3198       OpFunctionEnd
3199 )";
3200   CompileSuccessfully(spirv.c_str());
3201   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3202   EXPECT_THAT(getDiagnosticString(),
3203               HasSubstr("Target <id> '5[%5]'s type does not match "
3204                         "Source <id> '2[%uint]'s type."));
3205 }
3206 
TEST_F(ValidateIdWithMessage,OpCopyMemoryVoidTarget)3207 TEST_F(ValidateIdWithMessage, OpCopyMemoryVoidTarget) {
3208   const std::string spirv = kGLSL450MemoryModel + R"(
3209 %1 = OpTypeVoid
3210 %2 = OpTypeInt 32 0
3211 %3 = OpTypePointer Uniform %1
3212 %4 = OpTypePointer Uniform %2
3213 %5 = OpTypeFunction %1 %3 %4
3214 %6 = OpFunction %1 None %5
3215 %7 = OpFunctionParameter %3
3216 %8 = OpFunctionParameter %4
3217 %9 = OpLabel
3218 OpCopyMemory %7 %8
3219 OpReturn
3220 OpFunctionEnd
3221 )";
3222 
3223   CompileSuccessfully(spirv);
3224   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3225   EXPECT_THAT(getDiagnosticString(),
3226               HasSubstr("Target operand <id> '7[%7]' cannot be a void "
3227                         "pointer."));
3228 }
3229 
TEST_F(ValidateIdWithMessage,OpCopyMemoryVoidSource)3230 TEST_F(ValidateIdWithMessage, OpCopyMemoryVoidSource) {
3231   const std::string spirv = kGLSL450MemoryModel + R"(
3232 %1 = OpTypeVoid
3233 %2 = OpTypeInt 32 0
3234 %3 = OpTypePointer Uniform %1
3235 %4 = OpTypePointer Uniform %2
3236 %5 = OpTypeFunction %1 %3 %4
3237 %6 = OpFunction %1 None %5
3238 %7 = OpFunctionParameter %3
3239 %8 = OpFunctionParameter %4
3240 %9 = OpLabel
3241 OpCopyMemory %8 %7
3242 OpReturn
3243 OpFunctionEnd
3244 )";
3245 
3246   CompileSuccessfully(spirv);
3247   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3248   EXPECT_THAT(getDiagnosticString(),
3249               HasSubstr("Source operand <id> '7[%7]' cannot be a void "
3250                         "pointer."));
3251 }
3252 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedGood)3253 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedGood) {
3254   std::string spirv = kGLSL450MemoryModel + R"(
3255  %1 = OpTypeVoid
3256  %2 = OpTypeInt 32 0
3257  %3 = OpTypePointer UniformConstant %2
3258  %4 = OpTypePointer Function %2
3259  %5 = OpConstant %2 4
3260  %6 = OpVariable %3 UniformConstant %5
3261  %7 = OpTypeFunction %1
3262  %8 = OpFunction %1 None %7
3263  %9 = OpLabel
3264 %10 = OpVariable %4 Function
3265       OpCopyMemorySized %10 %6 %5 None
3266       OpReturn
3267       OpFunctionEnd)";
3268   CompileSuccessfully(spirv.c_str());
3269   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3270 }
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedTargetBad)3271 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedTargetBad) {
3272   std::string spirv = kGLSL450MemoryModel + R"(
3273 %1 = OpTypeVoid
3274 %2 = OpTypeInt 32 0
3275 %3 = OpTypePointer UniformConstant %2
3276 %4 = OpTypePointer Function %2
3277 %5 = OpConstant %2 4
3278 %6 = OpVariable %3 UniformConstant %5
3279 %7 = OpTypeFunction %1
3280 %8 = OpFunction %1 None %7
3281 %9 = OpLabel
3282      OpCopyMemorySized %5 %5 %5 None
3283      OpReturn
3284      OpFunctionEnd)";
3285   CompileSuccessfully(spirv.c_str());
3286   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3287   EXPECT_THAT(getDiagnosticString(),
3288               HasSubstr("Target operand <id> '5[%uint_4]' is not a pointer."));
3289 }
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSourceBad)3290 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSourceBad) {
3291   std::string spirv = kGLSL450MemoryModel + R"(
3292 %1 = OpTypeVoid
3293 %2 = OpTypeInt 32 0
3294 %3 = OpTypePointer UniformConstant %2
3295 %4 = OpTypePointer Function %2
3296 %5 = OpConstant %2 4
3297 %6 = OpTypeFunction %1
3298 %7 = OpFunction %1 None %6
3299 %8 = OpLabel
3300 %9 = OpVariable %4 Function
3301      OpCopyMemorySized %9 %5 %5 None
3302      OpReturn
3303      OpFunctionEnd)";
3304   CompileSuccessfully(spirv.c_str());
3305   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3306   EXPECT_THAT(getDiagnosticString(),
3307               HasSubstr("Source operand <id> '5[%uint_4]' is not a pointer."));
3308 }
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeBad)3309 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeBad) {
3310   std::string spirv = kGLSL450MemoryModel + R"(
3311  %1 = OpTypeVoid
3312  %2 = OpTypeInt 32 0
3313  %3 = OpTypePointer UniformConstant %2
3314  %4 = OpTypePointer Function %2
3315  %5 = OpConstant %2 4
3316  %6 = OpVariable %3 UniformConstant %5
3317  %7 = OpTypeFunction %1
3318  %8 = OpFunction %1 None %7
3319  %9 = OpLabel
3320 %10 = OpVariable %4 Function
3321       OpCopyMemorySized %10 %6 %6 None
3322       OpReturn
3323       OpFunctionEnd)";
3324   CompileSuccessfully(spirv.c_str());
3325   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3326   EXPECT_THAT(
3327       getDiagnosticString(),
3328       HasSubstr("Size operand <id> '6[%6]' must be a scalar integer type."));
3329 }
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeTypeBad)3330 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeTypeBad) {
3331   std::string spirv = kGLSL450MemoryModel + R"(
3332  %1 = OpTypeVoid
3333  %2 = OpTypeInt 32 0
3334  %3 = OpTypePointer UniformConstant %2
3335  %4 = OpTypePointer Function %2
3336  %5 = OpConstant %2 4
3337  %6 = OpVariable %3 UniformConstant %5
3338  %7 = OpTypeFunction %1
3339 %11 = OpTypeFloat 32
3340 %12 = OpConstant %11 1.0
3341  %8 = OpFunction %1 None %7
3342  %9 = OpLabel
3343 %10 = OpVariable %4 Function
3344       OpCopyMemorySized %10 %6 %12 None
3345       OpReturn
3346       OpFunctionEnd)";
3347   CompileSuccessfully(spirv.c_str());
3348   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3349   EXPECT_THAT(
3350       getDiagnosticString(),
3351       HasSubstr("Size operand <id> '9[%float_1]' must be a scalar integer "
3352                 "type."));
3353 }
3354 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeConstantNull)3355 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNull) {
3356   const std::string spirv = kGLSL450MemoryModel + R"(
3357 %1 = OpTypeVoid
3358 %2 = OpTypeInt 32 0
3359 %3 = OpConstantNull %2
3360 %4 = OpTypePointer Uniform %2
3361 %5 = OpTypeFloat 32
3362 %6 = OpTypePointer UniformConstant %5
3363 %7 = OpTypeFunction %1 %4 %6
3364 %8 = OpFunction %1 None %7
3365 %9 = OpFunctionParameter %4
3366 %10 = OpFunctionParameter %6
3367 %11 = OpLabel
3368 OpCopyMemorySized %9 %10 %3
3369 OpReturn
3370 OpFunctionEnd
3371 )";
3372 
3373   CompileSuccessfully(spirv);
3374   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3375   EXPECT_THAT(getDiagnosticString(),
3376               HasSubstr("Size operand <id> '3[%3]' cannot be a constant "
3377                         "zero."));
3378 }
3379 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeConstantZero)3380 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantZero) {
3381   const std::string spirv = kGLSL450MemoryModel + R"(
3382 %1 = OpTypeVoid
3383 %2 = OpTypeInt 32 0
3384 %3 = OpConstant %2 0
3385 %4 = OpTypePointer Uniform %2
3386 %5 = OpTypeFloat 32
3387 %6 = OpTypePointer UniformConstant %5
3388 %7 = OpTypeFunction %1 %4 %6
3389 %8 = OpFunction %1 None %7
3390 %9 = OpFunctionParameter %4
3391 %10 = OpFunctionParameter %6
3392 %11 = OpLabel
3393 OpCopyMemorySized %9 %10 %3
3394 OpReturn
3395 OpFunctionEnd
3396 )";
3397 
3398   CompileSuccessfully(spirv);
3399   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3400   EXPECT_THAT(getDiagnosticString(),
3401               HasSubstr("Size operand <id> '3[%uint_0]' cannot be a constant "
3402                         "zero."));
3403 }
3404 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeConstantZero64)3405 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantZero64) {
3406   const std::string spirv = kGLSL450MemoryModel + R"(
3407 %1 = OpTypeVoid
3408 %2 = OpTypeInt 64 0
3409 %3 = OpConstant %2 0
3410 %4 = OpTypePointer Uniform %2
3411 %5 = OpTypeFloat 32
3412 %6 = OpTypePointer UniformConstant %5
3413 %7 = OpTypeFunction %1 %4 %6
3414 %8 = OpFunction %1 None %7
3415 %9 = OpFunctionParameter %4
3416 %10 = OpFunctionParameter %6
3417 %11 = OpLabel
3418 OpCopyMemorySized %9 %10 %3
3419 OpReturn
3420 OpFunctionEnd
3421 )";
3422 
3423   CompileSuccessfully(spirv);
3424   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3425   EXPECT_THAT(getDiagnosticString(),
3426               HasSubstr("Size operand <id> '3[%ulong_0]' cannot be a constant "
3427                         "zero."));
3428 }
3429 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeConstantNegative)3430 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNegative) {
3431   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
3432 %1 = OpTypeVoid
3433 %2 = OpTypeInt 32 1
3434 %3 = OpConstant %2 -1
3435 %4 = OpTypePointer Uniform %2
3436 %5 = OpTypeFloat 32
3437 %6 = OpTypePointer UniformConstant %5
3438 %7 = OpTypeFunction %1 %4 %6
3439 %8 = OpFunction %1 None %7
3440 %9 = OpFunctionParameter %4
3441 %10 = OpFunctionParameter %6
3442 %11 = OpLabel
3443 OpCopyMemorySized %9 %10 %3
3444 OpReturn
3445 OpFunctionEnd
3446 )";
3447 
3448   CompileSuccessfully(spirv);
3449   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3450   EXPECT_THAT(
3451       getDiagnosticString(),
3452       HasSubstr("Size operand <id> '3[%int_n1]' cannot have the sign bit set "
3453                 "to 1."));
3454 }
3455 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeConstantNegative64)3456 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNegative64) {
3457   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
3458 %1 = OpTypeVoid
3459 %2 = OpTypeInt 64 1
3460 %3 = OpConstant %2 -1
3461 %4 = OpTypePointer Uniform %2
3462 %5 = OpTypeFloat 32
3463 %6 = OpTypePointer UniformConstant %5
3464 %7 = OpTypeFunction %1 %4 %6
3465 %8 = OpFunction %1 None %7
3466 %9 = OpFunctionParameter %4
3467 %10 = OpFunctionParameter %6
3468 %11 = OpLabel
3469 OpCopyMemorySized %9 %10 %3
3470 OpReturn
3471 OpFunctionEnd
3472 )";
3473 
3474   CompileSuccessfully(spirv);
3475   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3476   EXPECT_THAT(
3477       getDiagnosticString(),
3478       HasSubstr("Size operand <id> '3[%long_n1]' cannot have the sign bit set "
3479                 "to 1."));
3480 }
3481 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeUnsignedNegative)3482 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeUnsignedNegative) {
3483   const std::string spirv = kGLSL450MemoryModel + R"(
3484 %1 = OpTypeVoid
3485 %2 = OpTypeInt 32 0
3486 %3 = OpConstant %2 2147483648
3487 %4 = OpTypePointer Uniform %2
3488 %5 = OpTypeFloat 32
3489 %6 = OpTypePointer UniformConstant %5
3490 %7 = OpTypeFunction %1 %4 %6
3491 %8 = OpFunction %1 None %7
3492 %9 = OpFunctionParameter %4
3493 %10 = OpFunctionParameter %6
3494 %11 = OpLabel
3495 OpCopyMemorySized %9 %10 %3
3496 OpReturn
3497 OpFunctionEnd
3498 )";
3499 
3500   CompileSuccessfully(spirv);
3501   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3502 }
3503 
TEST_F(ValidateIdWithMessage,OpCopyMemorySizedSizeUnsignedNegative64)3504 TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeUnsignedNegative64) {
3505   const std::string spirv = kGLSL450MemoryModel + R"(
3506 %1 = OpTypeVoid
3507 %2 = OpTypeInt 64 0
3508 %3 = OpConstant %2 9223372036854775808
3509 %4 = OpTypePointer Uniform %2
3510 %5 = OpTypeFloat 32
3511 %6 = OpTypePointer UniformConstant %5
3512 %7 = OpTypeFunction %1 %4 %6
3513 %8 = OpFunction %1 None %7
3514 %9 = OpFunctionParameter %4
3515 %10 = OpFunctionParameter %6
3516 %11 = OpLabel
3517 OpCopyMemorySized %9 %10 %3
3518 OpReturn
3519 OpFunctionEnd
3520 )";
3521 
3522   CompileSuccessfully(spirv);
3523   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3524 }
3525 
3526 const char kDeeplyNestedStructureSetup[] = R"(
3527 %void = OpTypeVoid
3528 %void_f  = OpTypeFunction %void
3529 %int = OpTypeInt 32 0
3530 %float = OpTypeFloat 32
3531 %v3float = OpTypeVector %float 3
3532 %mat4x3 = OpTypeMatrix %v3float 4
3533 %_ptr_Private_mat4x3 = OpTypePointer Private %mat4x3
3534 %_ptr_Private_float = OpTypePointer Private %float
3535 %my_matrix = OpVariable %_ptr_Private_mat4x3 Private
3536 %my_float_var = OpVariable %_ptr_Private_float Private
3537 %_ptr_Function_float = OpTypePointer Function %float
3538 %int_0 = OpConstant %int 0
3539 %int_1 = OpConstant %int 1
3540 %int_2 = OpConstant %int 2
3541 %int_3 = OpConstant %int 3
3542 %int_5 = OpConstant %int 5
3543 
3544 ; Making the following nested structures.
3545 ;
3546 ; struct S {
3547 ;   bool b;
3548 ;   vec4 v[5];
3549 ;   int i;
3550 ;   mat4x3 m[5];
3551 ; }
3552 ; uniform blockName {
3553 ;   S s;
3554 ;   bool cond;
3555 ;   RunTimeArray arr;
3556 ; }
3557 
3558 %f32arr = OpTypeRuntimeArray %float
3559 %v4float = OpTypeVector %float 4
3560 %array5_mat4x3 = OpTypeArray %mat4x3 %int_5
3561 %array5_vec4 = OpTypeArray %v4float %int_5
3562 %_ptr_Uniform_float = OpTypePointer Uniform %float
3563 %_ptr_Function_vec4 = OpTypePointer Function %v4float
3564 %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float
3565 %struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3
3566 %struct_blockName = OpTypeStruct %struct_s %int %f32arr
3567 %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName
3568 %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s
3569 %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3
3570 %_ptr_Uniform_mat4x3 = OpTypePointer Uniform %mat4x3
3571 %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float
3572 %blockName_var = OpVariable %_ptr_Uniform_blockName Uniform
3573 %spec_int = OpSpecConstant %int 2
3574 %float_0 = OpConstant %float 0
3575 %func = OpFunction %void None %void_f
3576 %my_label = OpLabel
3577 )";
3578 
3579 // In what follows, Access Chain Instruction refers to one of the following:
3580 // OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, and
3581 // OpInBoundsPtrAccessChain
3582 using AccessChainInstructionTest = spvtest::ValidateBase<std::string>;
3583 
3584 // Determines whether the access chain instruction requires the 'element id'
3585 // argument.
AccessChainRequiresElemId(const std::string & instr)3586 bool AccessChainRequiresElemId(const std::string& instr) {
3587   return (instr == "OpPtrAccessChain" || instr == "OpInBoundsPtrAccessChain");
3588 }
3589 
3590 // Valid: Access a float in a matrix using an access chain instruction.
TEST_P(AccessChainInstructionTest,AccessChainGood)3591 TEST_P(AccessChainInstructionTest, AccessChainGood) {
3592   const std::string instr = GetParam();
3593   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3594   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup +
3595                       "%float_entry = " + instr +
3596                       R"( %_ptr_Private_float %my_matrix )" + elem +
3597                       R"(%int_0 %int_1
3598               OpReturn
3599               OpFunctionEnd
3600           )";
3601   CompileSuccessfully(spirv);
3602   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3603 }
3604 
3605 // Invalid. The result type of an access chain instruction must be a pointer.
TEST_P(AccessChainInstructionTest,AccessChainResultTypeBad)3606 TEST_P(AccessChainInstructionTest, AccessChainResultTypeBad) {
3607   const std::string instr = GetParam();
3608   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3609   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3610 %float_entry = )" +
3611                       instr +
3612                       R"( %float %my_matrix )" + elem +
3613                       R"(%int_0 %int_1
3614 OpReturn
3615 OpFunctionEnd
3616   )";
3617 
3618   const std::string expected_err = "The Result Type of " + instr +
3619                                    " <id> '36[%36]' must be "
3620                                    "OpTypePointer. Found OpTypeFloat.";
3621   CompileSuccessfully(spirv);
3622   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3623   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3624 }
3625 
3626 // Invalid. The base type of an access chain instruction must be a pointer.
TEST_P(AccessChainInstructionTest,AccessChainBaseTypeVoidBad)3627 TEST_P(AccessChainInstructionTest, AccessChainBaseTypeVoidBad) {
3628   const std::string instr = GetParam();
3629   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3630   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3631 %float_entry = )" +
3632                       instr + " %_ptr_Private_float %void " + elem +
3633                       R"(%int_0 %int_1
3634 OpReturn
3635 OpFunctionEnd
3636   )";
3637   CompileSuccessfully(spirv);
3638   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3639   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%void] cannot be a "
3640                                                "type"));
3641 }
3642 
3643 // Invalid. The base type of an access chain instruction must be a pointer.
TEST_P(AccessChainInstructionTest,AccessChainBaseTypeNonPtrVariableBad)3644 TEST_P(AccessChainInstructionTest, AccessChainBaseTypeNonPtrVariableBad) {
3645   const std::string instr = GetParam();
3646   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3647   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3648 %entry = )" +
3649                       instr + R"( %_ptr_Private_float %_ptr_Private_float )" +
3650                       elem +
3651                       R"(%int_0 %int_1
3652 OpReturn
3653 OpFunctionEnd
3654   )";
3655   CompileSuccessfully(spirv);
3656   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3657   EXPECT_THAT(getDiagnosticString(),
3658               HasSubstr("Operand 8[%_ptr_Private_float] cannot be a type"));
3659 }
3660 
3661 // Invalid: The storage class of Base and Result do not match.
TEST_P(AccessChainInstructionTest,AccessChainResultAndBaseStorageClassDoesntMatchBad)3662 TEST_P(AccessChainInstructionTest,
3663        AccessChainResultAndBaseStorageClassDoesntMatchBad) {
3664   const std::string instr = GetParam();
3665   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3666   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3667 %entry = )" +
3668                       instr + R"( %_ptr_Function_float %my_matrix )" + elem +
3669                       R"(%int_0 %int_1
3670 OpReturn
3671 OpFunctionEnd
3672   )";
3673   const std::string expected_err =
3674       "The result pointer storage class and base pointer storage class in " +
3675       instr + " do not match.";
3676   CompileSuccessfully(spirv);
3677   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3678   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3679 }
3680 
3681 // Invalid. The base type of an access chain instruction must point to a
3682 // composite object.
TEST_P(AccessChainInstructionTest,AccessChainBasePtrNotPointingToCompositeBad)3683 TEST_P(AccessChainInstructionTest,
3684        AccessChainBasePtrNotPointingToCompositeBad) {
3685   const std::string instr = GetParam();
3686   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3687   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3688 %entry = )" +
3689                       instr + R"( %_ptr_Private_float %my_float_var )" + elem +
3690                       R"(%int_0
3691 OpReturn
3692 OpFunctionEnd
3693   )";
3694   const std::string expected_err = instr +
3695                                    " reached non-composite type while "
3696                                    "indexes still remain to be traversed.";
3697   CompileSuccessfully(spirv);
3698   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3699   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3700 }
3701 
3702 // Valid. No Indexes were passed to the access chain instruction. The Result
3703 // Type is the same as the Base type.
TEST_P(AccessChainInstructionTest,AccessChainNoIndexesGood)3704 TEST_P(AccessChainInstructionTest, AccessChainNoIndexesGood) {
3705   const std::string instr = GetParam();
3706   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3707   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3708 %entry = )" +
3709                       instr + R"( %_ptr_Private_float %my_float_var )" + elem +
3710                       R"(
3711 OpReturn
3712 OpFunctionEnd
3713   )";
3714   CompileSuccessfully(spirv);
3715   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3716 }
3717 
3718 // Invalid. No Indexes were passed to the access chain instruction, but the
3719 // Result Type is different from the Base type.
TEST_P(AccessChainInstructionTest,AccessChainNoIndexesBad)3720 TEST_P(AccessChainInstructionTest, AccessChainNoIndexesBad) {
3721   const std::string instr = GetParam();
3722   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3723   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3724 %entry = )" +
3725                       instr + R"( %_ptr_Private_mat4x3 %my_float_var )" + elem +
3726                       R"(
3727 OpReturn
3728 OpFunctionEnd
3729   )";
3730   CompileSuccessfully(spirv);
3731   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3732   EXPECT_THAT(
3733       getDiagnosticString(),
3734       HasSubstr("result type (OpTypeMatrix) does not match the type that "
3735                 "results from indexing into the base <id> (OpTypeFloat)."));
3736 }
3737 
3738 // Valid: 255 indexes passed to the access chain instruction. Limit is 255.
TEST_P(AccessChainInstructionTest,AccessChainTooManyIndexesGood)3739 TEST_P(AccessChainInstructionTest, AccessChainTooManyIndexesGood) {
3740   const std::string instr = GetParam();
3741   const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
3742   int depth = 255;
3743   std::string header = kGLSL450MemoryModel + kDeeplyNestedStructureSetup;
3744   header.erase(header.find("%func"));
3745   std::ostringstream spirv;
3746   spirv << header << "\n";
3747 
3748   // Build nested structures. Struct 'i' contains struct 'i-1'
3749   spirv << "%s_depth_1 = OpTypeStruct %float\n";
3750   for (int i = 2; i <= depth; ++i) {
3751     spirv << "%s_depth_" << i << " = OpTypeStruct %s_depth_" << i - 1 << "\n";
3752   }
3753 
3754   // Define Pointer and Variable to use for the AccessChain instruction.
3755   spirv << "%_ptr_Uniform_deep_struct = OpTypePointer Uniform %s_depth_"
3756         << depth << "\n";
3757   spirv << "%deep_var = OpVariable %_ptr_Uniform_deep_struct Uniform\n";
3758 
3759   // Function Start
3760   spirv << R"(
3761   %func = OpFunction %void None %void_f
3762   %my_label = OpLabel
3763   )";
3764 
3765   // AccessChain with 'n' indexes (n = depth)
3766   spirv << "%entry = " << instr << " %_ptr_Uniform_float %deep_var" << elem;
3767   for (int i = 0; i < depth; ++i) {
3768     spirv << " %int_0";
3769   }
3770 
3771   // Function end
3772   spirv << R"(
3773     OpReturn
3774     OpFunctionEnd
3775   )";
3776   CompileSuccessfully(spirv.str());
3777   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3778 }
3779 
3780 // Invalid: 256 indexes passed to the access chain instruction. Limit is 255.
TEST_P(AccessChainInstructionTest,AccessChainTooManyIndexesBad)3781 TEST_P(AccessChainInstructionTest, AccessChainTooManyIndexesBad) {
3782   const std::string instr = GetParam();
3783   const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
3784   std::ostringstream spirv;
3785   spirv << kGLSL450MemoryModel << kDeeplyNestedStructureSetup;
3786   spirv << "%entry = " << instr << " %_ptr_Private_float %my_matrix" << elem;
3787   for (int i = 0; i < 256; ++i) {
3788     spirv << " %int_0";
3789   }
3790   spirv << R"(
3791     OpReturn
3792     OpFunctionEnd
3793   )";
3794   const std::string expected_err = "The number of indexes in " + instr +
3795                                    " may not exceed 255. Found 256 indexes.";
3796   CompileSuccessfully(spirv.str());
3797   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3798   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3799 }
3800 
3801 // Valid: 10 indexes passed to the access chain instruction. (Custom limit: 10)
TEST_P(AccessChainInstructionTest,CustomizedAccessChainTooManyIndexesGood)3802 TEST_P(AccessChainInstructionTest, CustomizedAccessChainTooManyIndexesGood) {
3803   const std::string instr = GetParam();
3804   const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
3805   int depth = 10;
3806   std::string header = kGLSL450MemoryModel + kDeeplyNestedStructureSetup;
3807   header.erase(header.find("%func"));
3808   std::ostringstream spirv;
3809   spirv << header << "\n";
3810 
3811   // Build nested structures. Struct 'i' contains struct 'i-1'
3812   spirv << "%s_depth_1 = OpTypeStruct %float\n";
3813   for (int i = 2; i <= depth; ++i) {
3814     spirv << "%s_depth_" << i << " = OpTypeStruct %s_depth_" << i - 1 << "\n";
3815   }
3816 
3817   // Define Pointer and Variable to use for the AccessChain instruction.
3818   spirv << "%_ptr_Uniform_deep_struct = OpTypePointer Uniform %s_depth_"
3819         << depth << "\n";
3820   spirv << "%deep_var = OpVariable %_ptr_Uniform_deep_struct Uniform\n";
3821 
3822   // Function Start
3823   spirv << R"(
3824   %func = OpFunction %void None %void_f
3825   %my_label = OpLabel
3826   )";
3827 
3828   // AccessChain with 'n' indexes (n = depth)
3829   spirv << "%entry = " << instr << " %_ptr_Uniform_float %deep_var" << elem;
3830   for (int i = 0; i < depth; ++i) {
3831     spirv << " %int_0";
3832   }
3833 
3834   // Function end
3835   spirv << R"(
3836     OpReturn
3837     OpFunctionEnd
3838   )";
3839 
3840   spvValidatorOptionsSetUniversalLimit(
3841       options_, spv_validator_limit_max_access_chain_indexes, 10u);
3842   CompileSuccessfully(spirv.str());
3843   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3844 }
3845 
3846 // Invalid: 11 indexes passed to the access chain instruction. Custom Limit:10
TEST_P(AccessChainInstructionTest,CustomizedAccessChainTooManyIndexesBad)3847 TEST_P(AccessChainInstructionTest, CustomizedAccessChainTooManyIndexesBad) {
3848   const std::string instr = GetParam();
3849   const std::string elem = AccessChainRequiresElemId(instr) ? " %int_0 " : "";
3850   std::ostringstream spirv;
3851   spirv << kGLSL450MemoryModel << kDeeplyNestedStructureSetup;
3852   spirv << "%entry = " << instr << " %_ptr_Private_float %my_matrix" << elem;
3853   for (int i = 0; i < 11; ++i) {
3854     spirv << " %int_0";
3855   }
3856   spirv << R"(
3857     OpReturn
3858     OpFunctionEnd
3859   )";
3860   const std::string expected_err = "The number of indexes in " + instr +
3861                                    " may not exceed 10. Found 11 indexes.";
3862   spvValidatorOptionsSetUniversalLimit(
3863       options_, spv_validator_limit_max_access_chain_indexes, 10u);
3864   CompileSuccessfully(spirv.str());
3865   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3866   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3867 }
3868 
3869 // Invalid: Index passed to the access chain instruction is float (must be
3870 // integer).
TEST_P(AccessChainInstructionTest,AccessChainUndefinedIndexBad)3871 TEST_P(AccessChainInstructionTest, AccessChainUndefinedIndexBad) {
3872   const std::string instr = GetParam();
3873   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3874   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3875 %entry = )" +
3876                       instr + R"( %_ptr_Private_float %my_matrix )" + elem +
3877                       R"(%float_0 %int_1
3878 OpReturn
3879 OpFunctionEnd
3880   )";
3881   const std::string expected_err =
3882       "Indexes passed to " + instr + " must be of type integer.";
3883   CompileSuccessfully(spirv);
3884   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3885   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3886 }
3887 
3888 // Invalid: The index argument that indexes into a struct must be of type
3889 // OpConstant.
TEST_P(AccessChainInstructionTest,AccessChainStructIndexNotConstantBad)3890 TEST_P(AccessChainInstructionTest, AccessChainStructIndexNotConstantBad) {
3891   const std::string instr = GetParam();
3892   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3893   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3894 %f = )" +
3895                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
3896                       R"(%int_0 %spec_int %int_2
3897 OpReturn
3898 OpFunctionEnd
3899   )";
3900   const std::string expected_err =
3901       "The <id> passed to " + instr +
3902       " to index into a structure must be an OpConstant.";
3903   CompileSuccessfully(spirv);
3904   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3905   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3906 }
3907 
3908 // Invalid: Indexing up to a vec4 granularity, but result type expected float.
TEST_P(AccessChainInstructionTest,AccessChainStructResultTypeDoesntMatchIndexedTypeBad)3909 TEST_P(AccessChainInstructionTest,
3910        AccessChainStructResultTypeDoesntMatchIndexedTypeBad) {
3911   const std::string instr = GetParam();
3912   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3913   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3914 %entry = )" +
3915                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
3916                       R"(%int_0 %int_1 %int_2
3917 OpReturn
3918 OpFunctionEnd
3919   )";
3920   const std::string expected_err = instr +
3921                                    " result type (OpTypeFloat) does not match "
3922                                    "the type that results from indexing into "
3923                                    "the base <id> (OpTypeVector).";
3924   CompileSuccessfully(spirv);
3925   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3926   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3927 }
3928 
3929 // Invalid: Reach non-composite type (bool) when unused indexes remain.
TEST_P(AccessChainInstructionTest,AccessChainStructTooManyIndexesBad)3930 TEST_P(AccessChainInstructionTest, AccessChainStructTooManyIndexesBad) {
3931   const std::string instr = GetParam();
3932   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3933   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3934 %entry = )" +
3935                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
3936                       R"(%int_0 %int_2 %int_2
3937 OpReturn
3938 OpFunctionEnd
3939   )";
3940   const std::string expected_err = instr +
3941                                    " reached non-composite type while "
3942                                    "indexes still remain to be traversed.";
3943   CompileSuccessfully(spirv);
3944   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3945   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3946 }
3947 
3948 // Invalid: Trying to find index 3 of the struct that has only 3 members.
TEST_P(AccessChainInstructionTest,AccessChainStructIndexOutOfBoundBad)3949 TEST_P(AccessChainInstructionTest, AccessChainStructIndexOutOfBoundBad) {
3950   const std::string instr = GetParam();
3951   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3952   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
3953 %entry = )" +
3954                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
3955                       R"(%int_3 %int_2 %int_2
3956 OpReturn
3957 OpFunctionEnd
3958   )";
3959   const std::string expected_err = "Index is out of bounds: " + instr +
3960                                    " can not find index 3 into the structure "
3961                                    "<id> '25[%_struct_25]'. This structure "
3962                                    "has 3 members. Largest valid index is 2.";
3963   CompileSuccessfully(spirv);
3964   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
3965   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
3966 }
3967 
3968 // Valid: Tests that we can index into Struct, Array, Matrix, and Vector!
TEST_P(AccessChainInstructionTest,AccessChainIndexIntoAllTypesGood)3969 TEST_P(AccessChainInstructionTest, AccessChainIndexIntoAllTypesGood) {
3970   // indexes that we are passing are: 0, 3, 1, 2, 0
3971   // 0 will select the struct_s within the base struct (blockName)
3972   // 3 will select the Array that contains 5 matrices
3973   // 1 will select the Matrix that is at index 1 of the array
3974   // 2 will select the column (which is a vector) within the matrix at index 2
3975   // 0 will select the element at the index 0 of the vector. (which is a float).
3976   const std::string instr = GetParam();
3977   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
3978   std::ostringstream spirv;
3979   spirv << kGLSL450MemoryModel << kDeeplyNestedStructureSetup << std::endl;
3980   spirv << "%ss = " << instr << " %_ptr_Uniform_struct_s %blockName_var "
3981         << elem << "%int_0" << std::endl;
3982   spirv << "%sa = " << instr << " %_ptr_Uniform_array5_mat4x3 %blockName_var "
3983         << elem << "%int_0 %int_3" << std::endl;
3984   spirv << "%sm = " << instr << " %_ptr_Uniform_mat4x3 %blockName_var " << elem
3985         << "%int_0 %int_3 %int_1" << std::endl;
3986   spirv << "%sc = " << instr << " %_ptr_Uniform_v3float %blockName_var " << elem
3987         << "%int_0 %int_3 %int_1 %int_2" << std::endl;
3988   spirv << "%entry = " << instr << " %_ptr_Uniform_float %blockName_var "
3989         << elem << "%int_0 %int_3 %int_1 %int_2 %int_0" << std::endl;
3990   spirv << R"(
3991 OpReturn
3992 OpFunctionEnd
3993   )";
3994   CompileSuccessfully(spirv.str());
3995   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
3996 }
3997 
3998 // Valid: Access an element of OpTypeRuntimeArray.
TEST_P(AccessChainInstructionTest,AccessChainIndexIntoRuntimeArrayGood)3999 TEST_P(AccessChainInstructionTest, AccessChainIndexIntoRuntimeArrayGood) {
4000   const std::string instr = GetParam();
4001   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
4002   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
4003 %runtime_arr_entry = )" +
4004                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
4005                       R"(%int_2 %int_0
4006 OpReturn
4007 OpFunctionEnd
4008   )";
4009   CompileSuccessfully(spirv);
4010   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4011 }
4012 
4013 // Invalid: Unused index when accessing OpTypeRuntimeArray.
TEST_P(AccessChainInstructionTest,AccessChainIndexIntoRuntimeArrayBad)4014 TEST_P(AccessChainInstructionTest, AccessChainIndexIntoRuntimeArrayBad) {
4015   const std::string instr = GetParam();
4016   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
4017   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
4018 %runtime_arr_entry = )" +
4019                       instr + R"( %_ptr_Uniform_float %blockName_var )" + elem +
4020                       R"(%int_2 %int_0 %int_1
4021 OpReturn
4022 OpFunctionEnd
4023   )";
4024   const std::string expected_err =
4025       instr +
4026       " reached non-composite type while indexes still remain to be traversed.";
4027   CompileSuccessfully(spirv);
4028   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4029   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
4030 }
4031 
4032 // Invalid: Reached scalar type before arguments to the access chain instruction
4033 // finished.
TEST_P(AccessChainInstructionTest,AccessChainMatrixMoreArgsThanNeededBad)4034 TEST_P(AccessChainInstructionTest, AccessChainMatrixMoreArgsThanNeededBad) {
4035   const std::string instr = GetParam();
4036   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
4037   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
4038 %entry = )" +
4039                       instr + R"( %_ptr_Private_float %my_matrix )" + elem +
4040                       R"(%int_0 %int_1 %int_0
4041 OpReturn
4042 OpFunctionEnd
4043   )";
4044   const std::string expected_err = instr +
4045                                    " reached non-composite type while "
4046                                    "indexes still remain to be traversed.";
4047   CompileSuccessfully(spirv);
4048   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4049   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
4050 }
4051 
4052 // Invalid: The result type and the type indexed into do not match.
TEST_P(AccessChainInstructionTest,AccessChainResultTypeDoesntMatchIndexedTypeBad)4053 TEST_P(AccessChainInstructionTest,
4054        AccessChainResultTypeDoesntMatchIndexedTypeBad) {
4055   const std::string instr = GetParam();
4056   const std::string elem = AccessChainRequiresElemId(instr) ? "%int_0 " : "";
4057   std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"(
4058 %entry = )" +
4059                       instr + R"( %_ptr_Private_mat4x3 %my_matrix )" + elem +
4060                       R"(%int_0 %int_1
4061 OpReturn
4062 OpFunctionEnd
4063   )";
4064   const std::string expected_err = instr +
4065                                    " result type (OpTypeMatrix) does not match "
4066                                    "the type that results from indexing into "
4067                                    "the base <id> (OpTypeFloat).";
4068   CompileSuccessfully(spirv);
4069   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4070   EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err));
4071 }
4072 
4073 // Run tests for Access Chain Instructions.
4074 INSTANTIATE_TEST_SUITE_P(
4075     CheckAccessChainInstructions, AccessChainInstructionTest,
4076     ::testing::Values("OpAccessChain", "OpInBoundsAccessChain",
4077                       "OpPtrAccessChain", "OpInBoundsPtrAccessChain"));
4078 
4079 // TODO: OpArrayLength
4080 // TODO: OpImagePointer
4081 // TODO: OpGenericPtrMemSemantics
4082 
TEST_F(ValidateIdWithMessage,OpFunctionGood)4083 TEST_F(ValidateIdWithMessage, OpFunctionGood) {
4084   std::string spirv = kGLSL450MemoryModel + R"(
4085 %1 = OpTypeVoid
4086 %2 = OpTypeInt 32 0
4087 %3 = OpTypeFunction %1 %2 %2
4088 %4 = OpFunction %1 None %3
4089 %5 = OpLabel
4090      OpReturn
4091      OpFunctionEnd)";
4092   CompileSuccessfully(spirv.c_str());
4093   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4094 }
TEST_F(ValidateIdWithMessage,OpFunctionResultTypeBad)4095 TEST_F(ValidateIdWithMessage, OpFunctionResultTypeBad) {
4096   std::string spirv = kGLSL450MemoryModel + R"(
4097 %1 = OpTypeVoid
4098 %2 = OpTypeInt 32 0
4099 %3 = OpConstant %2 42
4100 %4 = OpTypeFunction %1 %2 %2
4101 %5 = OpFunction %2 None %4
4102 %6 = OpLabel
4103      OpReturnValue %3
4104      OpFunctionEnd)";
4105   CompileSuccessfully(spirv.c_str());
4106   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4107   EXPECT_THAT(getDiagnosticString(),
4108               HasSubstr("OpFunction Result Type <id> '2[%uint]' does not "
4109                         "match the Function Type's return type <id> "
4110                         "'1[%void]'."));
4111 }
TEST_F(ValidateIdWithMessage,OpReturnValueTypeBad)4112 TEST_F(ValidateIdWithMessage, OpReturnValueTypeBad) {
4113   std::string spirv = kGLSL450MemoryModel + R"(
4114 %1 = OpTypeInt 32 0
4115 %2 = OpTypeFloat 32
4116 %3 = OpConstant %2 0
4117 %4 = OpTypeFunction %1
4118 %5 = OpFunction %1 None %4
4119 %6 = OpLabel
4120      OpReturnValue %3
4121      OpFunctionEnd)";
4122   CompileSuccessfully(spirv.c_str());
4123   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4124   EXPECT_THAT(getDiagnosticString(),
4125               HasSubstr("OpReturnValue Value <id> '3[%float_0]'s type does "
4126                         "not match OpFunction's return type."));
4127 }
TEST_F(ValidateIdWithMessage,OpFunctionFunctionTypeBad)4128 TEST_F(ValidateIdWithMessage, OpFunctionFunctionTypeBad) {
4129   std::string spirv = kGLSL450MemoryModel + R"(
4130 %1 = OpTypeVoid
4131 %2 = OpTypeInt 32 0
4132 %4 = OpFunction %1 None %2
4133 %5 = OpLabel
4134      OpReturn
4135 OpFunctionEnd)";
4136   CompileSuccessfully(spirv.c_str());
4137   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4138   EXPECT_THAT(
4139       getDiagnosticString(),
4140       HasSubstr("OpFunction Function Type <id> '2[%uint]' is not a function "
4141                 "type."));
4142 }
4143 
TEST_F(ValidateIdWithMessage,OpFunctionUseBad)4144 TEST_F(ValidateIdWithMessage, OpFunctionUseBad) {
4145   const std::string spirv = kGLSL450MemoryModel + R"(
4146 %1 = OpTypeFloat 32
4147 %2 = OpTypeFunction %1
4148 %3 = OpFunction %1 None %2
4149 %4 = OpLabel
4150 OpReturnValue %3
4151 OpFunctionEnd
4152 )";
4153 
4154   CompileSuccessfully(spirv);
4155   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4156   EXPECT_THAT(getDiagnosticString(),
4157               HasSubstr("Invalid use of function result id 3[%3]."));
4158 }
4159 
TEST_F(ValidateIdWithMessage,OpFunctionParameterGood)4160 TEST_F(ValidateIdWithMessage, OpFunctionParameterGood) {
4161   std::string spirv = kGLSL450MemoryModel + R"(
4162 %1 = OpTypeVoid
4163 %2 = OpTypeInt 32 0
4164 %3 = OpTypeFunction %1 %2
4165 %4 = OpFunction %1 None %3
4166 %5 = OpFunctionParameter %2
4167 %6 = OpLabel
4168      OpReturn
4169      OpFunctionEnd)";
4170   CompileSuccessfully(spirv.c_str());
4171   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4172 }
TEST_F(ValidateIdWithMessage,OpFunctionParameterMultipleGood)4173 TEST_F(ValidateIdWithMessage, OpFunctionParameterMultipleGood) {
4174   std::string spirv = kGLSL450MemoryModel + R"(
4175 %1 = OpTypeVoid
4176 %2 = OpTypeInt 32 0
4177 %3 = OpTypeFunction %1 %2 %2
4178 %4 = OpFunction %1 None %3
4179 %5 = OpFunctionParameter %2
4180 %6 = OpFunctionParameter %2
4181 %7 = OpLabel
4182      OpReturn
4183      OpFunctionEnd)";
4184   CompileSuccessfully(spirv.c_str());
4185   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4186 }
TEST_F(ValidateIdWithMessage,OpFunctionParameterResultTypeBad)4187 TEST_F(ValidateIdWithMessage, OpFunctionParameterResultTypeBad) {
4188   std::string spirv = kGLSL450MemoryModel + R"(
4189 %1 = OpTypeVoid
4190 %2 = OpTypeInt 32 0
4191 %3 = OpTypeFunction %1 %2
4192 %4 = OpFunction %1 None %3
4193 %5 = OpFunctionParameter %1
4194 %6 = OpLabel
4195      OpReturn
4196      OpFunctionEnd)";
4197   CompileSuccessfully(spirv.c_str());
4198   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4199   EXPECT_THAT(
4200       getDiagnosticString(),
4201       HasSubstr("OpFunctionParameter Result Type <id> '1[%void]' does not "
4202                 "match the OpTypeFunction parameter type of the same index."));
4203 }
4204 
TEST_F(ValidateIdWithMessage,OpFunctionCallGood)4205 TEST_F(ValidateIdWithMessage, OpFunctionCallGood) {
4206   std::string spirv = kGLSL450MemoryModel + R"(
4207 %1 = OpTypeVoid
4208 %2 = OpTypeInt 32 0
4209 %3 = OpTypeFunction %2 %2
4210 %4 = OpTypeFunction %1
4211 %5 = OpConstant %2 42 ;21
4212 
4213 %6 = OpFunction %2 None %3
4214 %7 = OpFunctionParameter %2
4215 %8 = OpLabel
4216      OpReturnValue %7
4217      OpFunctionEnd
4218 
4219 %10 = OpFunction %1 None %4
4220 %11 = OpLabel
4221 %12 = OpFunctionCall %2 %6 %5
4222       OpReturn
4223       OpFunctionEnd)";
4224   CompileSuccessfully(spirv.c_str());
4225   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4226 }
TEST_F(ValidateIdWithMessage,OpFunctionCallResultTypeBad)4227 TEST_F(ValidateIdWithMessage, OpFunctionCallResultTypeBad) {
4228   std::string spirv = kGLSL450MemoryModel + R"(
4229 %1 = OpTypeVoid
4230 %2 = OpTypeInt 32 0
4231 %3 = OpTypeFunction %2 %2
4232 %4 = OpTypeFunction %1
4233 %5 = OpConstant %2 42 ;21
4234 
4235 %6 = OpFunction %2 None %3
4236 %7 = OpFunctionParameter %2
4237 %8 = OpLabel
4238 %9 = OpIAdd %2 %7 %7
4239      OpReturnValue %9
4240      OpFunctionEnd
4241 
4242 %10 = OpFunction %1 None %4
4243 %11 = OpLabel
4244 %12 = OpFunctionCall %1 %6 %5
4245       OpReturn
4246       OpFunctionEnd)";
4247   CompileSuccessfully(spirv.c_str());
4248   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4249   EXPECT_THAT(getDiagnosticString(),
4250               HasSubstr("OpFunctionCall Result Type <id> '1[%void]'s type "
4251                         "does not match Function <id> '2[%uint]'s return "
4252                         "type."));
4253 }
TEST_F(ValidateIdWithMessage,OpFunctionCallFunctionBad)4254 TEST_F(ValidateIdWithMessage, OpFunctionCallFunctionBad) {
4255   std::string spirv = kGLSL450MemoryModel + R"(
4256 %1 = OpTypeVoid
4257 %2 = OpTypeInt 32 0
4258 %3 = OpTypeFunction %2 %2
4259 %4 = OpTypeFunction %1
4260 %5 = OpConstant %2 42 ;21
4261 
4262 %10 = OpFunction %1 None %4
4263 %11 = OpLabel
4264 %12 = OpFunctionCall %2 %5 %5
4265       OpReturn
4266       OpFunctionEnd)";
4267   CompileSuccessfully(spirv.c_str());
4268   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4269   EXPECT_THAT(getDiagnosticString(),
4270               HasSubstr("OpFunctionCall Function <id> '5[%uint_42]' is not a "
4271                         "function."));
4272 }
TEST_F(ValidateIdWithMessage,OpFunctionCallArgumentTypeBad)4273 TEST_F(ValidateIdWithMessage, OpFunctionCallArgumentTypeBad) {
4274   std::string spirv = kGLSL450MemoryModel + R"(
4275 %1 = OpTypeVoid
4276 %2 = OpTypeInt 32 0
4277 %3 = OpTypeFunction %2 %2
4278 %4 = OpTypeFunction %1
4279 %5 = OpConstant %2 42
4280 
4281 %13 = OpTypeFloat 32
4282 %14 = OpConstant %13 3.14
4283 
4284 %6 = OpFunction %2 None %3
4285 %7 = OpFunctionParameter %2
4286 %8 = OpLabel
4287 %9 = OpIAdd %2 %7 %7
4288      OpReturnValue %9
4289      OpFunctionEnd
4290 
4291 %10 = OpFunction %1 None %4
4292 %11 = OpLabel
4293 %12 = OpFunctionCall %2 %6 %14
4294       OpReturn
4295       OpFunctionEnd)";
4296   CompileSuccessfully(spirv.c_str());
4297   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4298   EXPECT_THAT(getDiagnosticString(),
4299               HasSubstr("OpFunctionCall Argument <id> '7[%float_3_1400001]'s "
4300                         "type does not match Function <id> '2[%uint]'s "
4301                         "parameter type."));
4302 }
4303 
4304 // Valid: OpSampledImage result <id> is used in the same block by
4305 // OpImageSampleImplictLod
TEST_F(ValidateIdWithMessage,OpSampledImageGood)4306 TEST_F(ValidateIdWithMessage, OpSampledImageGood) {
4307   std::string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
4308 %smpld_img = OpSampledImage %sampled_image_type %image_inst %sampler_inst
4309 %si_lod    = OpImageSampleImplicitLod %v4float %smpld_img %const_vec_1_1
4310     OpReturn
4311     OpFunctionEnd)";
4312   CompileSuccessfully(spirv.c_str());
4313   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4314 }
4315 
4316 // Invalid: OpSampledImage result <id> is defined in one block and used in a
4317 // different block.
TEST_F(ValidateIdWithMessage,OpSampledImageUsedInDifferentBlockBad)4318 TEST_F(ValidateIdWithMessage, OpSampledImageUsedInDifferentBlockBad) {
4319   std::string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
4320 %smpld_img = OpSampledImage %sampled_image_type %image_inst %sampler_inst
4321 OpBranch %label_2
4322 %label_2 = OpLabel
4323 %si_lod  = OpImageSampleImplicitLod %v4float %smpld_img %const_vec_1_1
4324 OpReturn
4325 OpFunctionEnd)";
4326   CompileSuccessfully(spirv.c_str());
4327   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4328   EXPECT_THAT(
4329       getDiagnosticString(),
4330       HasSubstr("All OpSampledImage instructions must be in the same block in "
4331                 "which their Result <id> are consumed. OpSampledImage Result "
4332                 "Type <id> '23[%23]' has a consumer in a different basic "
4333                 "block. The consumer instruction <id> is '25[%25]'."));
4334 }
4335 
4336 // Invalid: OpSampledImage result <id> is used by OpSelect
4337 // Note: According to the Spec, OpSelect parameters must be either a scalar or a
4338 // vector. Therefore, OpTypeSampledImage is an illegal parameter for OpSelect.
4339 // However, the OpSelect validation does not catch this today. Therefore, it is
4340 // caught by the OpSampledImage validation. If the OpSelect validation code is
4341 // updated, the error message for this test may change.
4342 //
4343 // Disabled since OpSelect catches this now.
TEST_F(ValidateIdWithMessage,DISABLED_OpSampledImageUsedInOpSelectBad)4344 TEST_F(ValidateIdWithMessage, DISABLED_OpSampledImageUsedInOpSelectBad) {
4345   std::string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
4346 %smpld_img  = OpSampledImage %sampled_image_type %image_inst %sampler_inst
4347 %select_img = OpSelect %sampled_image_type %spec_true %smpld_img %smpld_img
4348 OpReturn
4349 OpFunctionEnd)";
4350   CompileSuccessfully(spirv.c_str());
4351   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4352   EXPECT_THAT(getDiagnosticString(),
4353               HasSubstr("Result <id> from OpSampledImage instruction must not "
4354                         "appear as operands of OpSelect. Found result <id> "
4355                         "'23' as an operand of <id> '24'."));
4356 }
4357 
TEST_F(ValidateIdWithMessage,OpCopyObjectSampledImageGood)4358 TEST_F(ValidateIdWithMessage, OpCopyObjectSampledImageGood) {
4359   std::string spirv = kGLSL450MemoryModel + sampledImageSetup + R"(
4360 %smpld_img  = OpSampledImage %sampled_image_type %image_inst %sampler_inst
4361 %smpld_img2 = OpCopyObject %sampled_image_type %smpld_img
4362 %image_inst2 = OpCopyObject %image_type %image_inst
4363 OpReturn
4364 OpFunctionEnd)";
4365   CompileSuccessfully(spirv.c_str());
4366   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4367 }
4368 
4369 // Valid: Get a float in a matrix using CompositeExtract.
4370 // Valid: Insert float into a matrix using CompositeInsert.
TEST_F(ValidateIdWithMessage,CompositeExtractInsertGood)4371 TEST_F(ValidateIdWithMessage, CompositeExtractInsertGood) {
4372   std::ostringstream spirv;
4373   spirv << kGLSL450MemoryModel << kDeeplyNestedStructureSetup << std::endl;
4374   spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl;
4375   spirv << "%float_entry = OpCompositeExtract  %float %matrix 0 1" << std::endl;
4376 
4377   // To test CompositeInsert, insert the object back in after extraction.
4378   spirv << "%new_composite = OpCompositeInsert %mat4x3 %float_entry %matrix 0 1"
4379         << std::endl;
4380   spirv << R"(OpReturn
4381               OpFunctionEnd)";
4382   CompileSuccessfully(spirv.str());
4383   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4384 }
4385 
4386 #if 0
4387 TEST_F(ValidateIdWithMessage, OpFunctionCallArgumentCountBar) {
4388   const char *spirv = R"(
4389 %1 = OpTypeVoid
4390 %2 = OpTypeInt 32 0
4391 %3 = OpTypeFunction %2 %2
4392 %4 = OpTypeFunction %1
4393 %5 = OpConstant %2 42 ;21
4394 
4395 %6 = OpFunction %2 None %3
4396 %7 = OpFunctionParameter %2
4397 %8 = OpLabel
4398 %9 = OpLoad %2 %7
4399      OpReturnValue %9
4400      OpFunctionEnd
4401 
4402 %10 = OpFunction %1 None %4
4403 %11 = OpLabel
4404       OpReturn
4405 %12 = OpFunctionCall %2 %6 %5
4406       OpFunctionEnd)";
4407   CHECK(spirv, SPV_ERROR_INVALID_ID);
4408 }
4409 #endif
4410 
4411 // TODO: The many things that changed with how images are used.
4412 // TODO: OpTextureSample
4413 // TODO: OpTextureSampleDref
4414 // TODO: OpTextureSampleLod
4415 // TODO: OpTextureSampleProj
4416 // TODO: OpTextureSampleGrad
4417 // TODO: OpTextureSampleOffset
4418 // TODO: OpTextureSampleProjLod
4419 // TODO: OpTextureSampleProjGrad
4420 // TODO: OpTextureSampleLodOffset
4421 // TODO: OpTextureSampleProjOffset
4422 // TODO: OpTextureSampleGradOffset
4423 // TODO: OpTextureSampleProjLodOffset
4424 // TODO: OpTextureSampleProjGradOffset
4425 // TODO: OpTextureFetchTexelLod
4426 // TODO: OpTextureFetchTexelOffset
4427 // TODO: OpTextureFetchSample
4428 // TODO: OpTextureFetchTexel
4429 // TODO: OpTextureGather
4430 // TODO: OpTextureGatherOffset
4431 // TODO: OpTextureGatherOffsets
4432 // TODO: OpTextureQuerySizeLod
4433 // TODO: OpTextureQuerySize
4434 // TODO: OpTextureQueryLevels
4435 // TODO: OpTextureQuerySamples
4436 // TODO: OpConvertUToF
4437 // TODO: OpConvertFToS
4438 // TODO: OpConvertSToF
4439 // TODO: OpConvertUToF
4440 // TODO: OpUConvert
4441 // TODO: OpSConvert
4442 // TODO: OpFConvert
4443 // TODO: OpConvertPtrToU
4444 // TODO: OpConvertUToPtr
4445 // TODO: OpPtrCastToGeneric
4446 // TODO: OpGenericCastToPtr
4447 // TODO: OpBitcast
4448 // TODO: OpGenericCastToPtrExplicit
4449 // TODO: OpSatConvertSToU
4450 // TODO: OpSatConvertUToS
4451 // TODO: OpVectorExtractDynamic
4452 // TODO: OpVectorInsertDynamic
4453 
TEST_F(ValidateIdWithMessage,OpVectorShuffleIntGood)4454 TEST_F(ValidateIdWithMessage, OpVectorShuffleIntGood) {
4455   std::string spirv = kGLSL450MemoryModel + R"(
4456 %int = OpTypeInt 32 0
4457 %ivec3 = OpTypeVector %int 3
4458 %ivec4 = OpTypeVector %int 4
4459 %ptr_ivec3 = OpTypePointer Function %ivec3
4460 %undef = OpUndef %ivec4
4461 %int_42 = OpConstant %int 42
4462 %int_0 = OpConstant %int 0
4463 %int_2 = OpConstant %int 2
4464 %1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
4465 %2 = OpTypeFunction %ivec3
4466 %3 = OpFunction %ivec3 None %2
4467 %4 = OpLabel
4468 %var = OpVariable %ptr_ivec3 Function %1
4469 %5 = OpLoad %ivec3 %var
4470 %6 = OpVectorShuffle %ivec3 %5 %undef 2 1 0
4471      OpReturnValue %6
4472      OpFunctionEnd)";
4473   CompileSuccessfully(spirv.c_str());
4474   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4475 }
4476 
TEST_F(ValidateIdWithMessage,OpVectorShuffleFloatGood)4477 TEST_F(ValidateIdWithMessage, OpVectorShuffleFloatGood) {
4478   std::string spirv = kGLSL450MemoryModel + R"(
4479 %float = OpTypeFloat 32
4480 %vec2 = OpTypeVector %float 2
4481 %vec3 = OpTypeVector %float 3
4482 %vec4 = OpTypeVector %float 4
4483 %ptr_vec2 = OpTypePointer Function %vec2
4484 %ptr_vec3 = OpTypePointer Function %vec3
4485 %float_1 = OpConstant %float 1
4486 %float_2 = OpConstant %float 2
4487 %1 = OpConstantComposite %vec2 %float_2 %float_1
4488 %2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
4489 %3 = OpTypeFunction %vec4
4490 %4 = OpFunction %vec4 None %3
4491 %5 = OpLabel
4492 %var = OpVariable %ptr_vec2 Function %1
4493 %var2 = OpVariable %ptr_vec3 Function %2
4494 %6 = OpLoad %vec2 %var
4495 %7 = OpLoad %vec3 %var2
4496 %8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff
4497      OpReturnValue %8
4498      OpFunctionEnd)";
4499   CompileSuccessfully(spirv.c_str());
4500   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4501 }
4502 
TEST_F(ValidateIdWithMessage,OpVectorShuffleScalarResultType)4503 TEST_F(ValidateIdWithMessage, OpVectorShuffleScalarResultType) {
4504   std::string spirv = kGLSL450MemoryModel + R"(
4505 %float = OpTypeFloat 32
4506 %vec2 = OpTypeVector %float 2
4507 %ptr_vec2 = OpTypePointer Function %vec2
4508 %float_1 = OpConstant %float 1
4509 %float_2 = OpConstant %float 2
4510 %1 = OpConstantComposite %vec2 %float_2 %float_1
4511 %2 = OpTypeFunction %float
4512 %3 = OpFunction %float None %2
4513 %4 = OpLabel
4514 %var = OpVariable %ptr_vec2 Function %1
4515 %5 = OpLoad %vec2 %var
4516 %6 = OpVectorShuffle %float %5 %5 0
4517      OpReturnValue %6
4518      OpFunctionEnd)";
4519   CompileSuccessfully(spirv.c_str());
4520   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4521   EXPECT_THAT(
4522       getDiagnosticString(),
4523       HasSubstr("Result Type of OpVectorShuffle must be OpTypeVector."));
4524 }
4525 
TEST_F(ValidateIdWithMessage,OpVectorShuffleComponentCount)4526 TEST_F(ValidateIdWithMessage, OpVectorShuffleComponentCount) {
4527   std::string spirv = kGLSL450MemoryModel + R"(
4528 %int = OpTypeInt 32 0
4529 %ivec3 = OpTypeVector %int 3
4530 %ptr_ivec3 = OpTypePointer Function %ivec3
4531 %int_42 = OpConstant %int 42
4532 %int_0 = OpConstant %int 0
4533 %int_2 = OpConstant %int 2
4534 %1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
4535 %2 = OpTypeFunction %ivec3
4536 %3 = OpFunction %ivec3 None %2
4537 %4 = OpLabel
4538 %var = OpVariable %ptr_ivec3 Function %1
4539 %5 = OpLoad %ivec3 %var
4540 %6 = OpVectorShuffle %ivec3 %5 %5 0 1
4541      OpReturnValue %6
4542      OpFunctionEnd)";
4543   CompileSuccessfully(spirv.c_str());
4544   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4545   EXPECT_THAT(
4546       getDiagnosticString(),
4547       HasSubstr("OpVectorShuffle component literals count does not match "
4548                 "Result Type <id> '2[%v3uint]'s vector component count."));
4549 }
4550 
TEST_F(ValidateIdWithMessage,OpVectorShuffleVector1Type)4551 TEST_F(ValidateIdWithMessage, OpVectorShuffleVector1Type) {
4552   std::string spirv = kGLSL450MemoryModel + R"(
4553 %int = OpTypeInt 32 0
4554 %ivec2 = OpTypeVector %int 2
4555 %ptr_int = OpTypePointer Function %int
4556 %undef = OpUndef %ivec2
4557 %int_42 = OpConstant %int 42
4558 %2 = OpTypeFunction %ivec2
4559 %3 = OpFunction %ivec2 None %2
4560 %4 = OpLabel
4561 %var = OpVariable %ptr_int Function %int_42
4562 %5 = OpLoad %int %var
4563 %6 = OpVectorShuffle %ivec2 %5 %undef 0 0
4564      OpReturnValue %6
4565      OpFunctionEnd)";
4566   CompileSuccessfully(spirv.c_str());
4567   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4568   EXPECT_THAT(getDiagnosticString(),
4569               HasSubstr("The type of Vector 1 must be OpTypeVector."));
4570 }
4571 
TEST_F(ValidateIdWithMessage,OpVectorShuffleVector2Type)4572 TEST_F(ValidateIdWithMessage, OpVectorShuffleVector2Type) {
4573   std::string spirv = kGLSL450MemoryModel + R"(
4574 %int = OpTypeInt 32 0
4575 %ivec2 = OpTypeVector %int 2
4576 %ptr_ivec2 = OpTypePointer Function %ivec2
4577 %undef = OpUndef %int
4578 %int_42 = OpConstant %int 42
4579 %1 = OpConstantComposite %ivec2 %int_42 %int_42
4580 %2 = OpTypeFunction %ivec2
4581 %3 = OpFunction %ivec2 None %2
4582 %4 = OpLabel
4583 %var = OpVariable %ptr_ivec2 Function %1
4584 %5 = OpLoad %ivec2 %var
4585 %6 = OpVectorShuffle %ivec2 %5 %undef 0 1
4586      OpReturnValue %6
4587      OpFunctionEnd)";
4588   CompileSuccessfully(spirv.c_str());
4589   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4590   EXPECT_THAT(getDiagnosticString(),
4591               HasSubstr("The type of Vector 2 must be OpTypeVector."));
4592 }
4593 
TEST_F(ValidateIdWithMessage,OpVectorShuffleVector1ComponentType)4594 TEST_F(ValidateIdWithMessage, OpVectorShuffleVector1ComponentType) {
4595   std::string spirv = kGLSL450MemoryModel + R"(
4596 %int = OpTypeInt 32 0
4597 %ivec3 = OpTypeVector %int 3
4598 %ptr_ivec3 = OpTypePointer Function %ivec3
4599 %int_42 = OpConstant %int 42
4600 %int_0 = OpConstant %int 0
4601 %int_2 = OpConstant %int 2
4602 %float = OpTypeFloat 32
4603 %vec3 = OpTypeVector %float 3
4604 %vec4 = OpTypeVector %float 4
4605 %ptr_vec3 = OpTypePointer Function %vec3
4606 %float_1 = OpConstant %float 1
4607 %float_2 = OpConstant %float 2
4608 %1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
4609 %2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
4610 %3 = OpTypeFunction %vec4
4611 %4 = OpFunction %vec4 None %3
4612 %5 = OpLabel
4613 %var = OpVariable %ptr_ivec3 Function %1
4614 %var2 = OpVariable %ptr_vec3 Function %2
4615 %6 = OpLoad %ivec3 %var
4616 %7 = OpLoad %vec3 %var2
4617 %8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0
4618      OpReturnValue %8
4619      OpFunctionEnd)";
4620   CompileSuccessfully(spirv.c_str());
4621   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4622   EXPECT_THAT(getDiagnosticString(),
4623               HasSubstr("The Component Type of Vector 1 must be the same as "
4624                         "ResultType."));
4625 }
4626 
TEST_F(ValidateIdWithMessage,OpVectorShuffleVector2ComponentType)4627 TEST_F(ValidateIdWithMessage, OpVectorShuffleVector2ComponentType) {
4628   std::string spirv = kGLSL450MemoryModel + R"(
4629 %int = OpTypeInt 32 0
4630 %ivec3 = OpTypeVector %int 3
4631 %ptr_ivec3 = OpTypePointer Function %ivec3
4632 %int_42 = OpConstant %int 42
4633 %int_0 = OpConstant %int 0
4634 %int_2 = OpConstant %int 2
4635 %float = OpTypeFloat 32
4636 %vec3 = OpTypeVector %float 3
4637 %vec4 = OpTypeVector %float 4
4638 %ptr_vec3 = OpTypePointer Function %vec3
4639 %float_1 = OpConstant %float 1
4640 %float_2 = OpConstant %float 2
4641 %1 = OpConstantComposite %ivec3 %int_42 %int_0 %int_2
4642 %2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
4643 %3 = OpTypeFunction %vec4
4644 %4 = OpFunction %vec4 None %3
4645 %5 = OpLabel
4646 %var = OpVariable %ptr_ivec3 Function %1
4647 %var2 = OpVariable %ptr_vec3 Function %2
4648 %6 = OpLoad %vec3 %var2
4649 %7 = OpLoad %ivec3 %var
4650 %8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0
4651      OpReturnValue %8
4652      OpFunctionEnd)";
4653   CompileSuccessfully(spirv.c_str());
4654   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4655   EXPECT_THAT(getDiagnosticString(),
4656               HasSubstr("The Component Type of Vector 2 must be the same as "
4657                         "ResultType."));
4658 }
4659 
TEST_F(ValidateIdWithMessage,OpVectorShuffleLiterals)4660 TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) {
4661   std::string spirv = kGLSL450MemoryModel + R"(
4662 %float = OpTypeFloat 32
4663 %vec2 = OpTypeVector %float 2
4664 %vec3 = OpTypeVector %float 3
4665 %vec4 = OpTypeVector %float 4
4666 %ptr_vec2 = OpTypePointer Function %vec2
4667 %ptr_vec3 = OpTypePointer Function %vec3
4668 %float_1 = OpConstant %float 1
4669 %float_2 = OpConstant %float 2
4670 %1 = OpConstantComposite %vec2 %float_2 %float_1
4671 %2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
4672 %3 = OpTypeFunction %vec4
4673 %4 = OpFunction %vec4 None %3
4674 %5 = OpLabel
4675 %var = OpVariable %ptr_vec2 Function %1
4676 %var2 = OpVariable %ptr_vec3 Function %2
4677 %6 = OpLoad %vec2 %var
4678 %7 = OpLoad %vec3 %var2
4679 %8 = OpVectorShuffle %vec4 %6 %7 0 8 2 6
4680      OpReturnValue %8
4681      OpFunctionEnd)";
4682   CompileSuccessfully(spirv.c_str());
4683   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4684   EXPECT_THAT(
4685       getDiagnosticString(),
4686       HasSubstr(
4687           "Component index 8 is out of bounds for combined (Vector1 + Vector2) "
4688           "size of 5."));
4689 }
4690 
TEST_F(ValidateIdWithMessage,WebGPUOpVectorShuffle0xFFFFFFFFLiteralBad)4691 TEST_F(ValidateIdWithMessage, WebGPUOpVectorShuffle0xFFFFFFFFLiteralBad) {
4692   std::string spirv = R"(
4693     OpCapability Shader
4694     OpCapability VulkanMemoryModelKHR
4695     OpExtension "SPV_KHR_vulkan_memory_model"
4696     OpMemoryModel Logical VulkanKHR
4697 %float = OpTypeFloat 32
4698 %vec2 = OpTypeVector %float 2
4699 %vec3 = OpTypeVector %float 3
4700 %vec4 = OpTypeVector %float 4
4701 %ptr_vec2 = OpTypePointer Function %vec2
4702 %ptr_vec3 = OpTypePointer Function %vec3
4703 %float_1 = OpConstant %float 1
4704 %float_2 = OpConstant %float 2
4705 %1 = OpConstantComposite %vec2 %float_2 %float_1
4706 %2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2
4707 %3 = OpTypeFunction %vec4
4708 %4 = OpFunction %vec4 None %3
4709 %5 = OpLabel
4710 %var = OpVariable %ptr_vec2 Function %1
4711 %var2 = OpVariable %ptr_vec3 Function %2
4712 %6 = OpLoad %vec2 %var
4713 %7 = OpLoad %vec3 %var2
4714 %8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff
4715      OpReturnValue %8
4716      OpFunctionEnd)";
4717   CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0);
4718   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
4719   EXPECT_THAT(getDiagnosticString(),
4720               HasSubstr("Component literal at operand 3 cannot be 0xFFFFFFFF in"
4721                         " WebGPU execution environment."));
4722 }
4723 
4724 // TODO: OpCompositeConstruct
4725 // TODO: OpCompositeExtract
4726 // TODO: OpCompositeInsert
4727 // TODO: OpCopyObject
4728 // TODO: OpTranspose
4729 // TODO: OpSNegate
4730 // TODO: OpFNegate
4731 // TODO: OpNot
4732 // TODO: OpIAdd
4733 // TODO: OpFAdd
4734 // TODO: OpISub
4735 // TODO: OpFSub
4736 // TODO: OpIMul
4737 // TODO: OpFMul
4738 // TODO: OpUDiv
4739 // TODO: OpSDiv
4740 // TODO: OpFDiv
4741 // TODO: OpUMod
4742 // TODO: OpSRem
4743 // TODO: OpSMod
4744 // TODO: OpFRem
4745 // TODO: OpFMod
4746 // TODO: OpVectorTimesScalar
4747 // TODO: OpMatrixTimesScalar
4748 // TODO: OpVectorTimesMatrix
4749 // TODO: OpMatrixTimesVector
4750 // TODO: OpMatrixTimesMatrix
4751 // TODO: OpOuterProduct
4752 // TODO: OpDot
4753 // TODO: OpShiftRightLogical
4754 // TODO: OpShiftRightArithmetic
4755 // TODO: OpShiftLeftLogical
4756 // TODO: OpBitwiseOr
4757 // TODO: OpBitwiseXor
4758 // TODO: OpBitwiseAnd
4759 // TODO: OpAny
4760 // TODO: OpAll
4761 // TODO: OpIsNan
4762 // TODO: OpIsInf
4763 // TODO: OpIsFinite
4764 // TODO: OpIsNormal
4765 // TODO: OpSignBitSet
4766 // TODO: OpLessOrGreater
4767 // TODO: OpOrdered
4768 // TODO: OpUnordered
4769 // TODO: OpLogicalOr
4770 // TODO: OpLogicalXor
4771 // TODO: OpLogicalAnd
4772 // TODO: OpSelect
4773 // TODO: OpIEqual
4774 // TODO: OpFOrdEqual
4775 // TODO: OpFUnordEqual
4776 // TODO: OpINotEqual
4777 // TODO: OpFOrdNotEqual
4778 // TODO: OpFUnordNotEqual
4779 // TODO: OpULessThan
4780 // TODO: OpSLessThan
4781 // TODO: OpFOrdLessThan
4782 // TODO: OpFUnordLessThan
4783 // TODO: OpUGreaterThan
4784 // TODO: OpSGreaterThan
4785 // TODO: OpFOrdGreaterThan
4786 // TODO: OpFUnordGreaterThan
4787 // TODO: OpULessThanEqual
4788 // TODO: OpSLessThanEqual
4789 // TODO: OpFOrdLessThanEqual
4790 // TODO: OpFUnordLessThanEqual
4791 // TODO: OpUGreaterThanEqual
4792 // TODO: OpSGreaterThanEqual
4793 // TODO: OpFOrdGreaterThanEqual
4794 // TODO: OpFUnordGreaterThanEqual
4795 // TODO: OpDPdx
4796 // TODO: OpDPdy
4797 // TODO: OpFWidth
4798 // TODO: OpDPdxFine
4799 // TODO: OpDPdyFine
4800 // TODO: OpFwidthFine
4801 // TODO: OpDPdxCoarse
4802 // TODO: OpDPdyCoarse
4803 // TODO: OpFwidthCoarse
4804 // TODO: OpLoopMerge
4805 // TODO: OpSelectionMerge
4806 // TODO: OpBranch
4807 
TEST_F(ValidateIdWithMessage,OpPhiNotAType)4808 TEST_F(ValidateIdWithMessage, OpPhiNotAType) {
4809   std::string spirv = kOpenCLMemoryModel32 + R"(
4810 %2 = OpTypeBool
4811 %3 = OpConstantTrue %2
4812 %4 = OpTypeVoid
4813 %5 = OpTypeFunction %4
4814 %6 = OpFunction %4 None %5
4815 %7 = OpLabel
4816 OpBranch %8
4817 %8 = OpLabel
4818 %9 = OpPhi %3 %3 %7
4819 OpReturn
4820 OpFunctionEnd
4821   )";
4822 
4823   CompileSuccessfully(spirv.c_str());
4824   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4825   EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 3[%true] is not a type "
4826                                                "id"));
4827 }
4828 
TEST_F(ValidateIdWithMessage,OpPhiSamePredecessor)4829 TEST_F(ValidateIdWithMessage, OpPhiSamePredecessor) {
4830   std::string spirv = kOpenCLMemoryModel32 + R"(
4831 %2 = OpTypeBool
4832 %3 = OpConstantTrue %2
4833 %4 = OpTypeVoid
4834 %5 = OpTypeFunction %4
4835 %6 = OpFunction %4 None %5
4836 %7 = OpLabel
4837 OpBranchConditional %3 %8 %8
4838 %8 = OpLabel
4839 %9 = OpPhi %2 %3 %7
4840 OpReturn
4841 OpFunctionEnd
4842   )";
4843 
4844   CompileSuccessfully(spirv.c_str());
4845   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
4846 }
4847 
TEST_F(ValidateIdWithMessage,OpPhiOddArgumentNumber)4848 TEST_F(ValidateIdWithMessage, OpPhiOddArgumentNumber) {
4849   std::string spirv = kOpenCLMemoryModel32 + R"(
4850 %2 = OpTypeBool
4851 %3 = OpConstantTrue %2
4852 %4 = OpTypeVoid
4853 %5 = OpTypeFunction %4
4854 %6 = OpFunction %4 None %5
4855 %7 = OpLabel
4856 OpBranch %8
4857 %8 = OpLabel
4858 %9 = OpPhi %2 %3
4859 OpReturn
4860 OpFunctionEnd
4861   )";
4862 
4863   CompileSuccessfully(spirv.c_str());
4864   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4865   EXPECT_THAT(getDiagnosticString(),
4866               HasSubstr("OpPhi does not have an equal number of incoming "
4867                         "values and basic blocks."));
4868 }
4869 
TEST_F(ValidateIdWithMessage,OpPhiTooFewPredecessors)4870 TEST_F(ValidateIdWithMessage, OpPhiTooFewPredecessors) {
4871   std::string spirv = kOpenCLMemoryModel32 + R"(
4872 %2 = OpTypeBool
4873 %3 = OpConstantTrue %2
4874 %4 = OpTypeVoid
4875 %5 = OpTypeFunction %4
4876 %6 = OpFunction %4 None %5
4877 %7 = OpLabel
4878 OpBranch %8
4879 %8 = OpLabel
4880 %9 = OpPhi %2
4881 OpReturn
4882 OpFunctionEnd
4883   )";
4884 
4885   CompileSuccessfully(spirv.c_str());
4886   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4887   EXPECT_THAT(getDiagnosticString(),
4888               HasSubstr("OpPhi's number of incoming blocks (0) does not match "
4889                         "block's predecessor count (1)."));
4890 }
4891 
TEST_F(ValidateIdWithMessage,OpPhiTooManyPredecessors)4892 TEST_F(ValidateIdWithMessage, OpPhiTooManyPredecessors) {
4893   std::string spirv = kOpenCLMemoryModel32 + R"(
4894 %2 = OpTypeBool
4895 %3 = OpConstantTrue %2
4896 %4 = OpTypeVoid
4897 %5 = OpTypeFunction %4
4898 %6 = OpFunction %4 None %5
4899 %7 = OpLabel
4900 OpBranch %8
4901 %9 = OpLabel
4902 OpReturn
4903 %8 = OpLabel
4904 %10 = OpPhi %2 %3 %7 %3 %9
4905 OpReturn
4906 OpFunctionEnd
4907   )";
4908 
4909   CompileSuccessfully(spirv.c_str());
4910   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4911   EXPECT_THAT(getDiagnosticString(),
4912               HasSubstr("OpPhi's number of incoming blocks (2) does not match "
4913                         "block's predecessor count (1)."));
4914 }
4915 
TEST_F(ValidateIdWithMessage,OpPhiMismatchedTypes)4916 TEST_F(ValidateIdWithMessage, OpPhiMismatchedTypes) {
4917   std::string spirv = kOpenCLMemoryModel32 + R"(
4918 %2 = OpTypeBool
4919 %3 = OpConstantTrue %2
4920 %4 = OpTypeVoid
4921 %5 = OpTypeInt 32 0
4922 %6 = OpConstant %5 0
4923 %7 = OpTypeFunction %4
4924 %8 = OpFunction %4 None %7
4925 %9 = OpLabel
4926 OpBranchConditional %3 %10 %11
4927 %11 = OpLabel
4928 OpBranch %10
4929 %10 = OpLabel
4930 %12 = OpPhi %2 %3 %9 %6 %11
4931 OpReturn
4932 OpFunctionEnd
4933   )";
4934 
4935   CompileSuccessfully(spirv.c_str());
4936   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4937   EXPECT_THAT(getDiagnosticString(),
4938               HasSubstr("OpPhi's result type <id> 2[%bool] does not match "
4939                         "incoming value <id> 6[%uint_0] type <id> "
4940                         "5[%uint]."));
4941 }
4942 
TEST_F(ValidateIdWithMessage,OpPhiPredecessorNotABlock)4943 TEST_F(ValidateIdWithMessage, OpPhiPredecessorNotABlock) {
4944   std::string spirv = kOpenCLMemoryModel32 + R"(
4945 %2 = OpTypeBool
4946 %3 = OpConstantTrue %2
4947 %4 = OpTypeVoid
4948 %5 = OpTypeFunction %4
4949 %6 = OpFunction %4 None %5
4950 %7 = OpLabel
4951 OpBranchConditional %3 %8 %9
4952 %9 = OpLabel
4953 OpBranch %11
4954 %11 = OpLabel
4955 OpBranch %8
4956 %8 = OpLabel
4957 %10 = OpPhi %2 %3 %7 %3 %3
4958 OpReturn
4959 OpFunctionEnd
4960   )";
4961 
4962   CompileSuccessfully(spirv.c_str());
4963   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4964   EXPECT_THAT(getDiagnosticString(),
4965               HasSubstr("OpPhi's incoming basic block <id> 3[%true] is not an "
4966                         "OpLabel."));
4967 }
4968 
TEST_F(ValidateIdWithMessage,OpPhiNotAPredecessor)4969 TEST_F(ValidateIdWithMessage, OpPhiNotAPredecessor) {
4970   std::string spirv = kOpenCLMemoryModel32 + R"(
4971 %2 = OpTypeBool
4972 %3 = OpConstantTrue %2
4973 %4 = OpTypeVoid
4974 %5 = OpTypeFunction %4
4975 %6 = OpFunction %4 None %5
4976 %7 = OpLabel
4977 OpBranchConditional %3 %8 %9
4978 %9 = OpLabel
4979 OpBranch %11
4980 %11 = OpLabel
4981 OpBranch %8
4982 %8 = OpLabel
4983 %10 = OpPhi %2 %3 %7 %3 %9
4984 OpReturn
4985 OpFunctionEnd
4986   )";
4987 
4988   CompileSuccessfully(spirv.c_str());
4989   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
4990   EXPECT_THAT(getDiagnosticString(),
4991               HasSubstr("OpPhi's incoming basic block <id> 9[%9] is not a "
4992                         "predecessor of <id> 8[%8]."));
4993 }
4994 
TEST_F(ValidateIdWithMessage,OpBranchConditionalGood)4995 TEST_F(ValidateIdWithMessage, OpBranchConditionalGood) {
4996   std::string spirv = BranchConditionalSetup + R"(
4997     %branch_cond = OpINotEqual %bool %i0 %i1
4998                    OpSelectionMerge %end None
4999                    OpBranchConditional %branch_cond %target_t %target_f
5000   )" + BranchConditionalTail;
5001 
5002   CompileSuccessfully(spirv.c_str());
5003   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
5004 }
5005 
TEST_F(ValidateIdWithMessage,OpBranchConditionalWithWeightsGood)5006 TEST_F(ValidateIdWithMessage, OpBranchConditionalWithWeightsGood) {
5007   std::string spirv = BranchConditionalSetup + R"(
5008     %branch_cond = OpINotEqual %bool %i0 %i1
5009                    OpSelectionMerge %end None
5010                    OpBranchConditional %branch_cond %target_t %target_f 1 1
5011   )" + BranchConditionalTail;
5012 
5013   CompileSuccessfully(spirv.c_str());
5014   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
5015 }
5016 
TEST_F(ValidateIdWithMessage,OpBranchConditional_CondIsScalarInt)5017 TEST_F(ValidateIdWithMessage, OpBranchConditional_CondIsScalarInt) {
5018   std::string spirv = BranchConditionalSetup + R"(
5019                    OpSelectionMerge %end None
5020                    OpBranchConditional %i0 %target_t %target_f
5021   )" + BranchConditionalTail;
5022 
5023   CompileSuccessfully(spirv.c_str());
5024   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5025   EXPECT_THAT(
5026       getDiagnosticString(),
5027       HasSubstr(
5028           "Condition operand for OpBranchConditional must be of boolean type"));
5029 }
5030 
TEST_F(ValidateIdWithMessage,OpBranchConditional_TrueTargetIsNotLabel)5031 TEST_F(ValidateIdWithMessage, OpBranchConditional_TrueTargetIsNotLabel) {
5032   std::string spirv = BranchConditionalSetup + R"(
5033                    OpSelectionMerge %end None
5034                    OpBranchConditional %true %i0 %target_f
5035   )" + BranchConditionalTail;
5036 
5037   CompileSuccessfully(spirv.c_str());
5038   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5039   EXPECT_THAT(getDiagnosticString(),
5040               HasSubstr("The 'True Label' operand for OpBranchConditional must "
5041                         "be the ID of an OpLabel instruction"));
5042 }
5043 
TEST_F(ValidateIdWithMessage,OpBranchConditional_FalseTargetIsNotLabel)5044 TEST_F(ValidateIdWithMessage, OpBranchConditional_FalseTargetIsNotLabel) {
5045   std::string spirv = BranchConditionalSetup + R"(
5046                    OpSelectionMerge %end None
5047                    OpBranchConditional %true %target_t %i0
5048   )" + BranchConditionalTail;
5049 
5050   CompileSuccessfully(spirv.c_str());
5051   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5052   EXPECT_THAT(getDiagnosticString(),
5053               HasSubstr("The 'False Label' operand for OpBranchConditional "
5054                         "must be the ID of an OpLabel instruction"));
5055 }
5056 
TEST_F(ValidateIdWithMessage,OpBranchConditional_NotEnoughWeights)5057 TEST_F(ValidateIdWithMessage, OpBranchConditional_NotEnoughWeights) {
5058   std::string spirv = BranchConditionalSetup + R"(
5059     %branch_cond = OpINotEqual %bool %i0 %i1
5060                    OpSelectionMerge %end None
5061                    OpBranchConditional %branch_cond %target_t %target_f 1
5062   )" + BranchConditionalTail;
5063 
5064   CompileSuccessfully(spirv.c_str());
5065   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5066   EXPECT_THAT(
5067       getDiagnosticString(),
5068       HasSubstr("OpBranchConditional requires either 3 or 5 parameters"));
5069 }
5070 
TEST_F(ValidateIdWithMessage,OpBranchConditional_TooManyWeights)5071 TEST_F(ValidateIdWithMessage, OpBranchConditional_TooManyWeights) {
5072   std::string spirv = BranchConditionalSetup + R"(
5073     %branch_cond = OpINotEqual %bool %i0 %i1
5074                    OpSelectionMerge %end None
5075                    OpBranchConditional %branch_cond %target_t %target_f 1 2 3
5076   )" + BranchConditionalTail;
5077 
5078   CompileSuccessfully(spirv.c_str());
5079   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5080   EXPECT_THAT(
5081       getDiagnosticString(),
5082       HasSubstr("OpBranchConditional requires either 3 or 5 parameters"));
5083 }
5084 
TEST_F(ValidateIdWithMessage,OpBranchConditional_ConditionIsAType)5085 TEST_F(ValidateIdWithMessage, OpBranchConditional_ConditionIsAType) {
5086   std::string spirv = BranchConditionalSetup + R"(
5087 OpBranchConditional %bool %target_t %target_f
5088 )" + BranchConditionalTail;
5089 
5090   CompileSuccessfully(spirv.c_str());
5091   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5092   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 3[%bool] cannot be a "
5093                                                "type"));
5094 }
5095 
5096 // TODO: OpSwitch
5097 
TEST_F(ValidateIdWithMessage,OpReturnValueConstantGood)5098 TEST_F(ValidateIdWithMessage, OpReturnValueConstantGood) {
5099   std::string spirv = kGLSL450MemoryModel + R"(
5100 %1 = OpTypeVoid
5101 %2 = OpTypeInt 32 0
5102 %3 = OpTypeFunction %2
5103 %4 = OpConstant %2 42
5104 %5 = OpFunction %2 None %3
5105 %6 = OpLabel
5106      OpReturnValue %4
5107      OpFunctionEnd)";
5108   CompileSuccessfully(spirv.c_str());
5109   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5110 }
5111 
TEST_F(ValidateIdWithMessage,OpReturnValueVariableGood)5112 TEST_F(ValidateIdWithMessage, OpReturnValueVariableGood) {
5113   std::string spirv = kGLSL450MemoryModel + R"(
5114 %1 = OpTypeVoid
5115 %2 = OpTypeInt 32 0 ;10
5116 %3 = OpTypeFunction %2
5117 %8 = OpTypePointer Function %2 ;18
5118 %4 = OpConstant %2 42 ;22
5119 %5 = OpFunction %2 None %3 ;27
5120 %6 = OpLabel ;29
5121 %7 = OpVariable %8 Function %4 ;34
5122 %9 = OpLoad %2 %7
5123      OpReturnValue %9 ;36
5124      OpFunctionEnd)";
5125   CompileSuccessfully(spirv.c_str());
5126   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5127 }
5128 
TEST_F(ValidateIdWithMessage,OpReturnValueExpressionGood)5129 TEST_F(ValidateIdWithMessage, OpReturnValueExpressionGood) {
5130   std::string spirv = kGLSL450MemoryModel + R"(
5131 %1 = OpTypeVoid
5132 %2 = OpTypeInt 32 0
5133 %3 = OpTypeFunction %2
5134 %4 = OpConstant %2 42
5135 %5 = OpFunction %2 None %3
5136 %6 = OpLabel
5137 %7 = OpIAdd %2 %4 %4
5138      OpReturnValue %7
5139      OpFunctionEnd)";
5140   CompileSuccessfully(spirv.c_str());
5141   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5142 }
5143 
TEST_F(ValidateIdWithMessage,OpReturnValueIsType)5144 TEST_F(ValidateIdWithMessage, OpReturnValueIsType) {
5145   std::string spirv = kGLSL450MemoryModel + R"(
5146 %1 = OpTypeVoid
5147 %2 = OpTypeInt 32 0
5148 %3 = OpTypeFunction %2
5149 %5 = OpFunction %2 None %3
5150 %6 = OpLabel
5151      OpReturnValue %1
5152      OpFunctionEnd)";
5153   CompileSuccessfully(spirv.c_str());
5154   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5155   EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%void] cannot be a "
5156                                                "type"));
5157 }
5158 
TEST_F(ValidateIdWithMessage,OpReturnValueIsLabel)5159 TEST_F(ValidateIdWithMessage, OpReturnValueIsLabel) {
5160   std::string spirv = kGLSL450MemoryModel + R"(
5161 %1 = OpTypeVoid
5162 %2 = OpTypeInt 32 0
5163 %3 = OpTypeFunction %2
5164 %5 = OpFunction %2 None %3
5165 %6 = OpLabel
5166      OpReturnValue %6
5167      OpFunctionEnd)";
5168   CompileSuccessfully(spirv.c_str());
5169   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5170   EXPECT_THAT(getDiagnosticString(),
5171               HasSubstr("Operand 5[%5] requires a type"));
5172 }
5173 
TEST_F(ValidateIdWithMessage,OpReturnValueIsVoid)5174 TEST_F(ValidateIdWithMessage, OpReturnValueIsVoid) {
5175   std::string spirv = kGLSL450MemoryModel + R"(
5176 %1 = OpTypeVoid
5177 %2 = OpTypeInt 32 0
5178 %3 = OpTypeFunction %1
5179 %5 = OpFunction %1 None %3
5180 %6 = OpLabel
5181 %7 = OpFunctionCall %1 %5
5182      OpReturnValue %7
5183      OpFunctionEnd)";
5184   CompileSuccessfully(spirv.c_str());
5185   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5186   EXPECT_THAT(
5187       getDiagnosticString(),
5188       HasSubstr("OpReturnValue value's type <id> '1[%void]' is missing or "
5189                 "void."));
5190 }
5191 
TEST_F(ValidateIdWithMessage,OpReturnValueIsVariableInPhysical)5192 TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInPhysical) {
5193   // It's valid to return a pointer in a physical addressing model.
5194   std::string spirv = kOpCapabilitySetup + R"(
5195      OpMemoryModel Physical32 OpenCL
5196 %1 = OpTypeVoid
5197 %2 = OpTypeInt 32 0
5198 %3 = OpTypePointer Function %2
5199 %4 = OpTypeFunction %3
5200 %5 = OpFunction %3 None %4
5201 %6 = OpLabel
5202 %7 = OpVariable %3 Function
5203      OpReturnValue %7
5204      OpFunctionEnd)";
5205   CompileSuccessfully(spirv.c_str());
5206   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5207 }
5208 
TEST_F(ValidateIdWithMessage,OpReturnValueIsVariableInLogical)5209 TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInLogical) {
5210   // It's invalid to return a pointer in a physical addressing model.
5211   std::string spirv = kOpCapabilitySetup + R"(
5212      OpMemoryModel Logical GLSL450
5213 %1 = OpTypeVoid
5214 %2 = OpTypeInt 32 0
5215 %3 = OpTypePointer Function %2
5216 %4 = OpTypeFunction %3
5217 %5 = OpFunction %3 None %4
5218 %6 = OpLabel
5219 %7 = OpVariable %3 Function
5220      OpReturnValue %7
5221      OpFunctionEnd)";
5222   CompileSuccessfully(spirv.c_str());
5223   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5224   EXPECT_THAT(getDiagnosticString(),
5225               HasSubstr("OpReturnValue value's type <id> "
5226                         "'3[%_ptr_Function_uint]' is a pointer, which is "
5227                         "invalid in the Logical addressing model."));
5228 }
5229 
5230 // With the VariablePointer Capability, the return value of a function is
5231 // allowed to be a pointer.
TEST_F(ValidateIdWithMessage,OpReturnValueVarPtrGood)5232 TEST_F(ValidateIdWithMessage, OpReturnValueVarPtrGood) {
5233   std::ostringstream spirv;
5234   createVariablePointerSpirvProgram(&spirv,
5235                                     "" /* Instructions to add to "main" */,
5236                                     true /* Add VariablePointers Capability?*/,
5237                                     true /* Use Helper Function? */);
5238   CompileSuccessfully(spirv.str());
5239   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5240 }
5241 
5242 // Without the VariablePointer Capability, the return value of a function is
5243 // *not* allowed to be a pointer.
5244 // Disabled since using OpSelect with pointers without VariablePointers will
5245 // fail LogicalsPass.
TEST_F(ValidateIdWithMessage,DISABLED_OpReturnValueVarPtrBad)5246 TEST_F(ValidateIdWithMessage, DISABLED_OpReturnValueVarPtrBad) {
5247   std::ostringstream spirv;
5248   createVariablePointerSpirvProgram(&spirv,
5249                                     "" /* Instructions to add to "main" */,
5250                                     false /* Add VariablePointers Capability?*/,
5251                                     true /* Use Helper Function? */);
5252   CompileSuccessfully(spirv.str());
5253   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5254   EXPECT_THAT(getDiagnosticString(),
5255               HasSubstr("OpReturnValue value's type <id> '7' is a pointer, "
5256                         "which is invalid in the Logical addressing model."));
5257 }
5258 
5259 // TODO: enable when this bug is fixed:
5260 // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=15404
TEST_F(ValidateIdWithMessage,DISABLED_OpReturnValueIsFunction)5261 TEST_F(ValidateIdWithMessage, DISABLED_OpReturnValueIsFunction) {
5262   std::string spirv = kGLSL450MemoryModel + R"(
5263 %1 = OpTypeVoid
5264 %2 = OpTypeInt 32 0
5265 %3 = OpTypeFunction %2
5266 %5 = OpFunction %2 None %3
5267 %6 = OpLabel
5268      OpReturnValue %5
5269      OpFunctionEnd)";
5270   CompileSuccessfully(spirv.c_str());
5271   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5272 }
5273 
TEST_F(ValidateIdWithMessage,UndefinedTypeId)5274 TEST_F(ValidateIdWithMessage, UndefinedTypeId) {
5275   std::string spirv = kGLSL450MemoryModel + R"(
5276 %s = OpTypeStruct %i32
5277 )";
5278   CompileSuccessfully(spirv.c_str());
5279   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5280   EXPECT_THAT(getDiagnosticString(),
5281               HasSubstr("Operand 2[%2] requires a previous definition"));
5282 }
5283 
TEST_F(ValidateIdWithMessage,UndefinedIdScope)5284 TEST_F(ValidateIdWithMessage, UndefinedIdScope) {
5285   std::string spirv = kGLSL450MemoryModel + R"(
5286 %u32    = OpTypeInt 32 0
5287 %memsem = OpConstant %u32 0
5288 %void   = OpTypeVoid
5289 %void_f = OpTypeFunction %void
5290 %f      = OpFunction %void None %void_f
5291 %l      = OpLabel
5292           OpMemoryBarrier %undef %memsem
5293           OpReturn
5294           OpFunctionEnd
5295 )";
5296   CompileSuccessfully(spirv.c_str());
5297   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5298   EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7[%7] has not been "
5299                                                "defined"));
5300 }
5301 
TEST_F(ValidateIdWithMessage,UndefinedIdMemSem)5302 TEST_F(ValidateIdWithMessage, UndefinedIdMemSem) {
5303   std::string spirv = kGLSL450MemoryModel + R"(
5304 %u32    = OpTypeInt 32 0
5305 %scope  = OpConstant %u32 0
5306 %void   = OpTypeVoid
5307 %void_f = OpTypeFunction %void
5308 %f      = OpFunction %void None %void_f
5309 %l      = OpLabel
5310           OpMemoryBarrier %scope %undef
5311           OpReturn
5312           OpFunctionEnd
5313 )";
5314   CompileSuccessfully(spirv.c_str());
5315   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5316   EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7[%7] has not been "
5317                                                "defined"));
5318 }
5319 
TEST_F(ValidateIdWithMessage,KernelOpEntryPointAndOpInBoundsPtrAccessChainGood)5320 TEST_F(ValidateIdWithMessage,
5321        KernelOpEntryPointAndOpInBoundsPtrAccessChainGood) {
5322   std::string spirv = kOpenCLMemoryModel32 + R"(
5323       OpEntryPoint Kernel %2 "simple_kernel"
5324       OpSource OpenCL_C 200000
5325       OpDecorate %3 BuiltIn GlobalInvocationId
5326       OpDecorate %3 Constant
5327       OpDecorate %4 FuncParamAttr NoCapture
5328       OpDecorate %3 LinkageAttributes "__spirv_GlobalInvocationId" Import
5329  %5 = OpTypeInt 32 0
5330  %6 = OpTypeVector %5 3
5331  %7 = OpTypePointer UniformConstant %6
5332  %3 = OpVariable %7 UniformConstant
5333  %8 = OpTypeVoid
5334  %9 = OpTypeStruct %5
5335 %10 = OpTypePointer CrossWorkgroup %9
5336 %11 = OpTypeFunction %8 %10
5337 %12 = OpConstant %5 0
5338 %13 = OpTypePointer CrossWorkgroup %5
5339 %14 = OpConstant %5 42
5340  %2 = OpFunction %8 None %11
5341  %4 = OpFunctionParameter %10
5342 %15 = OpLabel
5343 %16 = OpLoad %6 %3 Aligned 0
5344 %17 = OpCompositeExtract %5 %16 0
5345 %18 = OpInBoundsPtrAccessChain %13 %4 %17 %12
5346       OpStore %18 %14 Aligned 4
5347       OpReturn
5348       OpFunctionEnd)";
5349   CompileSuccessfully(spirv.c_str());
5350   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5351 }
5352 
TEST_F(ValidateIdWithMessage,OpPtrAccessChainGood)5353 TEST_F(ValidateIdWithMessage, OpPtrAccessChainGood) {
5354   std::string spirv = kOpenCLMemoryModel64 + R"(
5355       OpEntryPoint Kernel %2 "another_kernel"
5356       OpSource OpenCL_C 200000
5357       OpDecorate %3 BuiltIn GlobalInvocationId
5358       OpDecorate %3 Constant
5359       OpDecorate %4 FuncParamAttr NoCapture
5360       OpDecorate %3 LinkageAttributes "__spirv_GlobalInvocationId" Import
5361  %5 = OpTypeInt 64 0
5362  %6 = OpTypeVector %5 3
5363  %7 = OpTypePointer UniformConstant %6
5364  %3 = OpVariable %7 UniformConstant
5365  %8 = OpTypeVoid
5366  %9 = OpTypeInt 32 0
5367 %10 = OpTypeStruct %9
5368 %11 = OpTypePointer CrossWorkgroup %10
5369 %12 = OpTypeFunction %8 %11
5370 %13 = OpConstant %5 4294967295
5371 %14 = OpConstant %9 0
5372 %15 = OpTypePointer CrossWorkgroup %9
5373 %16 = OpConstant %9 42
5374  %2 = OpFunction %8 None %12
5375  %4 = OpFunctionParameter %11
5376 %17 = OpLabel
5377 %18 = OpLoad %6 %3 Aligned 0
5378 %19 = OpCompositeExtract %5 %18 0
5379 %20 = OpBitwiseAnd %5 %19 %13
5380 %21 = OpPtrAccessChain %15 %4 %20 %14
5381       OpStore %21 %16 Aligned 4
5382       OpReturn
5383       OpFunctionEnd)";
5384   CompileSuccessfully(spirv.c_str());
5385   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5386 }
5387 
TEST_F(ValidateIdWithMessage,StgBufOpPtrAccessChainGood)5388 TEST_F(ValidateIdWithMessage, StgBufOpPtrAccessChainGood) {
5389   std::string spirv = R"(
5390      OpCapability Shader
5391      OpCapability Linkage
5392      OpCapability VariablePointersStorageBuffer
5393      OpExtension "SPV_KHR_variable_pointers"
5394      OpMemoryModel Logical GLSL450
5395      OpEntryPoint GLCompute %3 ""
5396 %int = OpTypeInt 32 0
5397 %int_2 = OpConstant %int 2
5398 %int_4 = OpConstant %int 4
5399 %struct = OpTypeStruct %int
5400 %array = OpTypeArray %struct %int_4
5401 %ptr = OpTypePointer StorageBuffer %array
5402 %var = OpVariable %ptr StorageBuffer
5403 %1 = OpTypeVoid
5404 %2 = OpTypeFunction %1
5405 %3 = OpFunction %1 None %2
5406 %4 = OpLabel
5407 %5 = OpPtrAccessChain %ptr %var %int_2
5408      OpReturn
5409      OpFunctionEnd
5410 )";
5411   CompileSuccessfully(spirv.c_str());
5412   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5413 }
5414 
TEST_F(ValidateIdWithMessage,OpLoadBitcastPointerGood)5415 TEST_F(ValidateIdWithMessage, OpLoadBitcastPointerGood) {
5416   std::string spirv = kOpenCLMemoryModel64 + R"(
5417 %2  = OpTypeVoid
5418 %3  = OpTypeInt 32 0
5419 %4  = OpTypeFloat 32
5420 %5  = OpTypePointer UniformConstant %3
5421 %6  = OpTypePointer UniformConstant %4
5422 %7  = OpVariable %5 UniformConstant
5423 %8  = OpTypeFunction %2
5424 %9  = OpFunction %2 None %8
5425 %10 = OpLabel
5426 %11 = OpBitcast %6 %7
5427 %12 = OpLoad %4 %11
5428       OpReturn
5429       OpFunctionEnd)";
5430   CompileSuccessfully(spirv.c_str());
5431   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5432 }
TEST_F(ValidateIdWithMessage,OpLoadBitcastNonPointerBad)5433 TEST_F(ValidateIdWithMessage, OpLoadBitcastNonPointerBad) {
5434   std::string spirv = kOpenCLMemoryModel64 + R"(
5435 %2  = OpTypeVoid
5436 %3  = OpTypeInt 32 0
5437 %4  = OpTypeFloat 32
5438 %5  = OpTypePointer UniformConstant %3
5439 %6  = OpTypeFunction %2
5440 %7  = OpVariable %5 UniformConstant
5441 %8  = OpFunction %2 None %6
5442 %9  = OpLabel
5443 %10 = OpLoad %3 %7
5444 %11 = OpBitcast %4 %10
5445 %12 = OpLoad %3 %11
5446       OpReturn
5447       OpFunctionEnd)";
5448   CompileSuccessfully(spirv.c_str());
5449   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5450   EXPECT_THAT(
5451       getDiagnosticString(),
5452       HasSubstr("OpLoad type for pointer <id> '11[%11]' is not a pointer "
5453                 "type."));
5454 }
TEST_F(ValidateIdWithMessage,OpStoreBitcastPointerGood)5455 TEST_F(ValidateIdWithMessage, OpStoreBitcastPointerGood) {
5456   std::string spirv = kOpenCLMemoryModel64 + R"(
5457 %2  = OpTypeVoid
5458 %3  = OpTypeInt 32 0
5459 %4  = OpTypeFloat 32
5460 %5  = OpTypePointer Function %3
5461 %6  = OpTypePointer Function %4
5462 %7  = OpTypeFunction %2
5463 %8  = OpConstant %3 42
5464 %9  = OpFunction %2 None %7
5465 %10 = OpLabel
5466 %11 = OpVariable %6 Function
5467 %12 = OpBitcast %5 %11
5468       OpStore %12 %8
5469       OpReturn
5470       OpFunctionEnd)";
5471   CompileSuccessfully(spirv.c_str());
5472   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
5473 }
TEST_F(ValidateIdWithMessage,OpStoreBitcastNonPointerBad)5474 TEST_F(ValidateIdWithMessage, OpStoreBitcastNonPointerBad) {
5475   std::string spirv = kOpenCLMemoryModel64 + R"(
5476 %2  = OpTypeVoid
5477 %3  = OpTypeInt 32 0
5478 %4  = OpTypeFloat 32
5479 %5  = OpTypePointer Function %4
5480 %6  = OpTypeFunction %2
5481 %7  = OpConstant %4 42
5482 %8  = OpFunction %2 None %6
5483 %9  = OpLabel
5484 %10 = OpVariable %5 Function
5485 %11 = OpBitcast %3 %7
5486       OpStore %11 %7
5487       OpReturn
5488       OpFunctionEnd)";
5489   CompileSuccessfully(spirv.c_str());
5490   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5491   EXPECT_THAT(
5492       getDiagnosticString(),
5493       HasSubstr("OpStore type for pointer <id> '11[%11]' is not a pointer "
5494                 "type."));
5495 }
5496 
5497 // Result <id> resulting from an instruction within a function may not be used
5498 // outside that function.
TEST_F(ValidateIdWithMessage,ResultIdUsedOutsideOfFunctionBad)5499 TEST_F(ValidateIdWithMessage, ResultIdUsedOutsideOfFunctionBad) {
5500   std::string spirv = kGLSL450MemoryModel + R"(
5501 %1 = OpTypeVoid
5502 %2 = OpTypeFunction %1
5503 %3 = OpTypeInt 32 0
5504 %4 = OpTypePointer Function %3
5505 %5 = OpFunction %1 None %2
5506 %6 = OpLabel
5507 %7 = OpVariable %4 Function
5508 OpReturn
5509 OpFunctionEnd
5510 %8 = OpFunction %1 None %2
5511 %9 = OpLabel
5512 %10 = OpLoad %3 %7
5513 OpReturn
5514 OpFunctionEnd
5515   )";
5516   CompileSuccessfully(spirv.c_str());
5517   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5518   EXPECT_THAT(
5519       getDiagnosticString(),
5520       HasSubstr(
5521           "ID 7[%7] defined in block 6[%6] does not dominate its use in block "
5522           "9[%9]"));
5523 }
5524 
TEST_F(ValidateIdWithMessage,SpecIdTargetNotSpecializationConstant)5525 TEST_F(ValidateIdWithMessage, SpecIdTargetNotSpecializationConstant) {
5526   std::string spirv = kGLSL450MemoryModel + R"(
5527 OpDecorate %1 SpecId 200
5528 %void = OpTypeVoid
5529 %2 = OpTypeFunction %void
5530 %int = OpTypeInt 32 0
5531 %1 = OpConstant %int 3
5532 %main = OpFunction %void None %2
5533 %4 = OpLabel
5534 OpReturnValue %1
5535 OpFunctionEnd
5536   )";
5537   CompileSuccessfully(spirv.c_str());
5538   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5539   EXPECT_THAT(getDiagnosticString(),
5540               HasSubstr("OpDecorate SpecId decoration target <id> "
5541                         "'1[%uint_3]' is not a scalar specialization "
5542                         "constant."));
5543 }
5544 
TEST_F(ValidateIdWithMessage,SpecIdTargetOpSpecConstantOpBad)5545 TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantOpBad) {
5546   std::string spirv = kGLSL450MemoryModel + R"(
5547 OpDecorate %1 SpecId 200
5548 %void = OpTypeVoid
5549 %2 = OpTypeFunction %void
5550 %int = OpTypeInt 32 0
5551 %3 = OpConstant %int 1
5552 %4 = OpConstant %int 2
5553 %1 = OpSpecConstantOp %int IAdd %3 %4
5554 %main = OpFunction %void None %2
5555 %6 = OpLabel
5556 OpReturnValue %3
5557 OpFunctionEnd
5558   )";
5559   CompileSuccessfully(spirv.c_str());
5560   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5561   EXPECT_THAT(getDiagnosticString(),
5562               HasSubstr("OpDecorate SpecId decoration target <id> '1[%1]' is "
5563                         "not a scalar specialization constant."));
5564 }
5565 
TEST_F(ValidateIdWithMessage,SpecIdTargetOpSpecConstantCompositeBad)5566 TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantCompositeBad) {
5567   std::string spirv = kGLSL450MemoryModel + R"(
5568 OpDecorate %1 SpecId 200
5569 %void = OpTypeVoid
5570 %2 = OpTypeFunction %void
5571 %int = OpTypeInt 32 0
5572 %3 = OpConstant %int 1
5573 %1 = OpSpecConstantComposite %int
5574 %main = OpFunction %void None %2
5575 %4 = OpLabel
5576 OpReturnValue %3
5577 OpFunctionEnd
5578   )";
5579   CompileSuccessfully(spirv.c_str());
5580   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5581   EXPECT_THAT(getDiagnosticString(),
5582               HasSubstr("OpDecorate SpecId decoration target <id> '1[%1]' is "
5583                         "not a scalar specialization constant."));
5584 }
5585 
TEST_F(ValidateIdWithMessage,SpecIdTargetGood)5586 TEST_F(ValidateIdWithMessage, SpecIdTargetGood) {
5587   std::string spirv = kGLSL450MemoryModel + R"(
5588 OpDecorate %3 SpecId 200
5589 OpDecorate %4 SpecId 201
5590 OpDecorate %5 SpecId 202
5591 %1 = OpTypeVoid
5592 %2 = OpTypeFunction %1
5593 %int = OpTypeInt 32 0
5594 %bool = OpTypeBool
5595 %3 = OpSpecConstant %int 3
5596 %4 = OpSpecConstantTrue %bool
5597 %5 = OpSpecConstantFalse %bool
5598 %main = OpFunction %1 None %2
5599 %6 = OpLabel
5600 OpReturn
5601 OpFunctionEnd
5602   )";
5603   CompileSuccessfully(spirv.c_str());
5604   EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
5605 }
5606 
TEST_F(ValidateIdWithMessage,CorrectErrorForShuffle)5607 TEST_F(ValidateIdWithMessage, CorrectErrorForShuffle) {
5608   std::string spirv = kGLSL450MemoryModel + R"(
5609    %uint = OpTypeInt 32 0
5610   %float = OpTypeFloat 32
5611 %v4float = OpTypeVector %float 4
5612 %v2float = OpTypeVector %float 2
5613    %void = OpTypeVoid
5614     %548 = OpTypeFunction %void
5615      %CS = OpFunction %void None %548
5616     %550 = OpLabel
5617    %6275 = OpUndef %v2float
5618    %6280 = OpUndef %v2float
5619    %6282 = OpVectorShuffle %v4float %6275 %6280 0 1 4 5
5620            OpReturn
5621            OpFunctionEnd
5622   )";
5623 
5624   CompileSuccessfully(spirv.c_str());
5625   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5626   EXPECT_THAT(
5627       getDiagnosticString(),
5628       HasSubstr(
5629           "Component index 4 is out of bounds for combined (Vector1 + Vector2) "
5630           "size of 4."));
5631   EXPECT_EQ(25, getErrorPosition().index);
5632 }
5633 
TEST_F(ValidateIdWithMessage,VoidStructMember)5634 TEST_F(ValidateIdWithMessage, VoidStructMember) {
5635   const std::string spirv = kGLSL450MemoryModel + R"(
5636 %void = OpTypeVoid
5637 %struct = OpTypeStruct %void
5638 )";
5639 
5640   CompileSuccessfully(spirv);
5641   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5642   EXPECT_THAT(getDiagnosticString(),
5643               HasSubstr("Structures cannot contain a void type."));
5644 }
5645 
TEST_F(ValidateIdWithMessage,TypeFunctionBadUse)5646 TEST_F(ValidateIdWithMessage, TypeFunctionBadUse) {
5647   std::string spirv = kGLSL450MemoryModel + R"(
5648 %1 = OpTypeVoid
5649 %2 = OpTypeFunction %1
5650 %3 = OpTypePointer Function %2
5651 %4 = OpFunction %1 None %2
5652 %5 = OpLabel
5653      OpReturn
5654      OpFunctionEnd)";
5655 
5656   CompileSuccessfully(spirv);
5657   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5658   EXPECT_THAT(getDiagnosticString(),
5659               HasSubstr("Invalid use of function type result id 2[%2]."));
5660 }
5661 
TEST_F(ValidateIdWithMessage,BadTypeId)5662 TEST_F(ValidateIdWithMessage, BadTypeId) {
5663   std::string spirv = kGLSL450MemoryModel + R"(
5664           %1 = OpTypeVoid
5665           %2 = OpTypeFunction %1
5666           %3 = OpTypeFloat 32
5667           %4 = OpConstant %3 0
5668           %5 = OpFunction %1 None %2
5669           %6 = OpLabel
5670           %7 = OpUndef %4
5671                OpReturn
5672                OpFunctionEnd
5673 )";
5674 
5675   CompileSuccessfully(spirv);
5676   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
5677   EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 4[%float_0] is not a type "
5678                                                "id"));
5679 }
5680 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelLoadMakePointerVisibleGood)5681 TEST_F(ValidateIdWithMessage, VulkanMemoryModelLoadMakePointerVisibleGood) {
5682   std::string spirv = R"(
5683 OpCapability Shader
5684 OpCapability VulkanMemoryModelKHR
5685 OpCapability Linkage
5686 OpExtension "SPV_KHR_vulkan_memory_model"
5687 OpMemoryModel Logical VulkanKHR
5688 %1 = OpTypeVoid
5689 %2 = OpTypeInt 32 0
5690 %3 = OpTypePointer Workgroup %2
5691 %4 = OpVariable %3 Workgroup
5692 %5 = OpTypeFunction %1
5693 %6 = OpConstant %2 2
5694 %7 = OpFunction %1 None %5
5695 %8 = OpLabel
5696 %9 = OpLoad %2 %4 NonPrivatePointerKHR|MakePointerVisibleKHR %6
5697 OpReturn
5698 OpFunctionEnd
5699 )";
5700 
5701   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5702   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5703 }
5704 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelLoadMakePointerVisibleMissingNonPrivatePointer)5705 TEST_F(ValidateIdWithMessage,
5706        VulkanMemoryModelLoadMakePointerVisibleMissingNonPrivatePointer) {
5707   std::string spirv = R"(
5708 OpCapability Shader
5709 OpCapability VulkanMemoryModelKHR
5710 OpCapability Linkage
5711 OpExtension "SPV_KHR_vulkan_memory_model"
5712 OpMemoryModel Logical VulkanKHR
5713 %1 = OpTypeVoid
5714 %2 = OpTypeInt 32 0
5715 %3 = OpTypePointer Workgroup %2
5716 %4 = OpVariable %3 Workgroup
5717 %5 = OpTypeFunction %1
5718 %6 = OpConstant %2 2
5719 %7 = OpFunction %1 None %5
5720 %8 = OpLabel
5721 %9 = OpLoad %2 %4 MakePointerVisibleKHR %6
5722 OpReturn
5723 OpFunctionEnd
5724 )";
5725 
5726   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5727   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5728   EXPECT_THAT(getDiagnosticString(),
5729               HasSubstr("NonPrivatePointerKHR must be specified if "
5730                         "MakePointerVisibleKHR is specified."));
5731 }
5732 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelLoadNonPrivatePointerBadStorageClass)5733 TEST_F(ValidateIdWithMessage,
5734        VulkanMemoryModelLoadNonPrivatePointerBadStorageClass) {
5735   std::string spirv = R"(
5736 OpCapability Shader
5737 OpCapability VulkanMemoryModelKHR
5738 OpCapability Linkage
5739 OpExtension "SPV_KHR_vulkan_memory_model"
5740 OpMemoryModel Logical VulkanKHR
5741 %1 = OpTypeVoid
5742 %2 = OpTypeInt 32 0
5743 %3 = OpTypePointer Private %2
5744 %4 = OpVariable %3 Private
5745 %5 = OpTypeFunction %1
5746 %6 = OpConstant %2 2
5747 %7 = OpFunction %1 None %5
5748 %8 = OpLabel
5749 %9 = OpLoad %2 %4 NonPrivatePointerKHR
5750 OpReturn
5751 OpFunctionEnd
5752 )";
5753 
5754   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5755   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5756   EXPECT_THAT(getDiagnosticString(),
5757               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
5758                         "Workgroup, CrossWorkgroup, Generic, Image or "
5759                         "StorageBuffer storage classes."));
5760 }
5761 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelLoadMakePointerAvailableCannotBeUsed)5762 TEST_F(ValidateIdWithMessage,
5763        VulkanMemoryModelLoadMakePointerAvailableCannotBeUsed) {
5764   std::string spirv = R"(
5765 OpCapability Shader
5766 OpCapability VulkanMemoryModelKHR
5767 OpCapability Linkage
5768 OpExtension "SPV_KHR_vulkan_memory_model"
5769 OpMemoryModel Logical VulkanKHR
5770 %1 = OpTypeVoid
5771 %2 = OpTypeInt 32 0
5772 %3 = OpTypePointer Workgroup %2
5773 %4 = OpVariable %3 Workgroup
5774 %5 = OpTypeFunction %1
5775 %6 = OpConstant %2 2
5776 %7 = OpFunction %1 None %5
5777 %8 = OpLabel
5778 %9 = OpLoad %2 %4 NonPrivatePointerKHR|MakePointerAvailableKHR %6
5779 OpReturn
5780 OpFunctionEnd
5781 )";
5782 
5783   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5784   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5785   EXPECT_THAT(getDiagnosticString(),
5786               HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad"));
5787 }
5788 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelStoreMakePointerAvailableGood)5789 TEST_F(ValidateIdWithMessage, VulkanMemoryModelStoreMakePointerAvailableGood) {
5790   std::string spirv = R"(
5791 OpCapability Shader
5792 OpCapability VulkanMemoryModelKHR
5793 OpCapability Linkage
5794 OpExtension "SPV_KHR_vulkan_memory_model"
5795 OpMemoryModel Logical VulkanKHR
5796 %1 = OpTypeVoid
5797 %2 = OpTypeInt 32 0
5798 %3 = OpTypePointer Uniform %2
5799 %4 = OpVariable %3 Uniform
5800 %5 = OpTypeFunction %1
5801 %6 = OpConstant %2 5
5802 %7 = OpFunction %1 None %5
5803 %8 = OpLabel
5804 OpStore %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR %6
5805 OpReturn
5806 OpFunctionEnd
5807 )";
5808 
5809   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5810   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5811 }
5812 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelStoreMakePointerAvailableMissingNonPrivatePointer)5813 TEST_F(ValidateIdWithMessage,
5814        VulkanMemoryModelStoreMakePointerAvailableMissingNonPrivatePointer) {
5815   std::string spirv = R"(
5816 OpCapability Shader
5817 OpCapability VulkanMemoryModelKHR
5818 OpCapability Linkage
5819 OpExtension "SPV_KHR_vulkan_memory_model"
5820 OpMemoryModel Logical VulkanKHR
5821 %1 = OpTypeVoid
5822 %2 = OpTypeInt 32 0
5823 %3 = OpTypePointer Uniform %2
5824 %4 = OpVariable %3 Uniform
5825 %5 = OpTypeFunction %1
5826 %6 = OpConstant %2 5
5827 %7 = OpFunction %1 None %5
5828 %8 = OpLabel
5829 OpStore %4 %6 MakePointerAvailableKHR %6
5830 OpReturn
5831 OpFunctionEnd
5832 )";
5833 
5834   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5835   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5836   EXPECT_THAT(getDiagnosticString(),
5837               HasSubstr("NonPrivatePointerKHR must be specified if "
5838                         "MakePointerAvailableKHR is specified."));
5839 }
5840 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelStoreNonPrivatePointerBadStorageClass)5841 TEST_F(ValidateIdWithMessage,
5842        VulkanMemoryModelStoreNonPrivatePointerBadStorageClass) {
5843   std::string spirv = R"(
5844 OpCapability Shader
5845 OpCapability VulkanMemoryModelKHR
5846 OpCapability Linkage
5847 OpExtension "SPV_KHR_vulkan_memory_model"
5848 OpMemoryModel Logical VulkanKHR
5849 %1 = OpTypeVoid
5850 %2 = OpTypeInt 32 0
5851 %3 = OpTypePointer Output %2
5852 %4 = OpVariable %3 Output
5853 %5 = OpTypeFunction %1
5854 %6 = OpConstant %2 5
5855 %7 = OpFunction %1 None %5
5856 %8 = OpLabel
5857 OpStore %4 %6 NonPrivatePointerKHR
5858 OpReturn
5859 OpFunctionEnd
5860 )";
5861 
5862   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5863   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5864   EXPECT_THAT(getDiagnosticString(),
5865               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
5866                         "Workgroup, CrossWorkgroup, Generic, Image or "
5867                         "StorageBuffer storage classes."));
5868 }
5869 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelStoreMakePointerVisibleCannotBeUsed)5870 TEST_F(ValidateIdWithMessage,
5871        VulkanMemoryModelStoreMakePointerVisibleCannotBeUsed) {
5872   std::string spirv = R"(
5873 OpCapability Shader
5874 OpCapability VulkanMemoryModelKHR
5875 OpCapability Linkage
5876 OpExtension "SPV_KHR_vulkan_memory_model"
5877 OpMemoryModel Logical VulkanKHR
5878 %1 = OpTypeVoid
5879 %2 = OpTypeInt 32 0
5880 %3 = OpTypePointer Uniform %2
5881 %4 = OpVariable %3 Uniform
5882 %5 = OpTypeFunction %1
5883 %6 = OpConstant %2 5
5884 %7 = OpFunction %1 None %5
5885 %8 = OpLabel
5886 OpStore %4 %6 NonPrivatePointerKHR|MakePointerVisibleKHR %6
5887 OpReturn
5888 OpFunctionEnd
5889 )";
5890 
5891   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5892   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5893   EXPECT_THAT(getDiagnosticString(),
5894               HasSubstr("MakePointerVisibleKHR cannot be used with OpStore."));
5895 }
5896 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryAvailable)5897 TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryAvailable) {
5898   std::string spirv = R"(
5899 OpCapability Shader
5900 OpCapability Linkage
5901 OpCapability VulkanMemoryModelKHR
5902 OpExtension "SPV_KHR_vulkan_memory_model"
5903 OpMemoryModel Logical VulkanKHR
5904 %1 = OpTypeVoid
5905 %2 = OpTypeInt 32 0
5906 %3 = OpTypePointer Workgroup %2
5907 %4 = OpVariable %3 Workgroup
5908 %5 = OpTypePointer Uniform %2
5909 %6 = OpVariable %5 Uniform
5910 %7 = OpConstant %2 2
5911 %8 = OpConstant %2 5
5912 %9 = OpTypeFunction %1
5913 %10 = OpFunction %1 None %9
5914 %11 = OpLabel
5915 OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR %7
5916 OpReturn
5917 OpFunctionEnd
5918 )";
5919 
5920   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5921   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5922 }
5923 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryVisible)5924 TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryVisible) {
5925   std::string spirv = R"(
5926 OpCapability Shader
5927 OpCapability Linkage
5928 OpCapability VulkanMemoryModelKHR
5929 OpExtension "SPV_KHR_vulkan_memory_model"
5930 OpMemoryModel Logical VulkanKHR
5931 %1 = OpTypeVoid
5932 %2 = OpTypeInt 32 0
5933 %3 = OpTypePointer Workgroup %2
5934 %4 = OpVariable %3 Workgroup
5935 %5 = OpTypePointer Uniform %2
5936 %6 = OpVariable %5 Uniform
5937 %7 = OpConstant %2 2
5938 %8 = OpConstant %2 5
5939 %9 = OpTypeFunction %1
5940 %10 = OpFunction %1 None %9
5941 %11 = OpLabel
5942 OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerVisibleKHR %8
5943 OpReturn
5944 OpFunctionEnd
5945 )";
5946 
5947   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5948   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5949 }
5950 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryAvailableAndVisible)5951 TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryAvailableAndVisible) {
5952   std::string spirv = R"(
5953 OpCapability Shader
5954 OpCapability Linkage
5955 OpCapability VulkanMemoryModelKHR
5956 OpExtension "SPV_KHR_vulkan_memory_model"
5957 OpMemoryModel Logical VulkanKHR
5958 %1 = OpTypeVoid
5959 %2 = OpTypeInt 32 0
5960 %3 = OpTypePointer Workgroup %2
5961 %4 = OpVariable %3 Workgroup
5962 %5 = OpTypePointer Uniform %2
5963 %6 = OpVariable %5 Uniform
5964 %7 = OpConstant %2 2
5965 %8 = OpConstant %2 5
5966 %9 = OpTypeFunction %1
5967 %10 = OpFunction %1 None %9
5968 %11 = OpLabel
5969 OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8
5970 OpReturn
5971 OpFunctionEnd
5972 )";
5973 
5974   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
5975   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
5976 }
5977 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryAvailableMissingNonPrivatePointer)5978 TEST_F(ValidateIdWithMessage,
5979        VulkanMemoryModelCopyMemoryAvailableMissingNonPrivatePointer) {
5980   std::string spirv = R"(
5981 OpCapability Shader
5982 OpCapability Linkage
5983 OpCapability VulkanMemoryModelKHR
5984 OpExtension "SPV_KHR_vulkan_memory_model"
5985 OpMemoryModel Logical VulkanKHR
5986 %1 = OpTypeVoid
5987 %2 = OpTypeInt 32 0
5988 %3 = OpTypePointer Workgroup %2
5989 %4 = OpVariable %3 Workgroup
5990 %5 = OpTypePointer Uniform %2
5991 %6 = OpVariable %5 Uniform
5992 %7 = OpConstant %2 2
5993 %8 = OpConstant %2 5
5994 %9 = OpTypeFunction %1
5995 %10 = OpFunction %1 None %9
5996 %11 = OpLabel
5997 OpCopyMemory %4 %6 MakePointerAvailableKHR %7
5998 OpReturn
5999 OpFunctionEnd
6000 )";
6001 
6002   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6003   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6004   EXPECT_THAT(getDiagnosticString(),
6005               HasSubstr("NonPrivatePointerKHR must be specified if "
6006                         "MakePointerAvailableKHR is specified."));
6007 }
6008 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryVisibleMissingNonPrivatePointer)6009 TEST_F(ValidateIdWithMessage,
6010        VulkanMemoryModelCopyMemoryVisibleMissingNonPrivatePointer) {
6011   std::string spirv = R"(
6012 OpCapability Shader
6013 OpCapability Linkage
6014 OpCapability VulkanMemoryModelKHR
6015 OpExtension "SPV_KHR_vulkan_memory_model"
6016 OpMemoryModel Logical VulkanKHR
6017 %1 = OpTypeVoid
6018 %2 = OpTypeInt 32 0
6019 %3 = OpTypePointer Workgroup %2
6020 %4 = OpVariable %3 Workgroup
6021 %5 = OpTypePointer Uniform %2
6022 %6 = OpVariable %5 Uniform
6023 %7 = OpConstant %2 2
6024 %8 = OpConstant %2 5
6025 %9 = OpTypeFunction %1
6026 %10 = OpFunction %1 None %9
6027 %11 = OpLabel
6028 OpCopyMemory %4 %6 MakePointerVisibleKHR %8
6029 OpReturn
6030 OpFunctionEnd
6031 )";
6032 
6033   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6034   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6035   EXPECT_THAT(getDiagnosticString(),
6036               HasSubstr("NonPrivatePointerKHR must be specified if "
6037                         "MakePointerVisibleKHR is specified."));
6038 }
6039 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryAvailableBadStorageClass)6040 TEST_F(ValidateIdWithMessage,
6041        VulkanMemoryModelCopyMemoryAvailableBadStorageClass) {
6042   std::string spirv = R"(
6043 OpCapability Shader
6044 OpCapability Linkage
6045 OpCapability VulkanMemoryModelKHR
6046 OpExtension "SPV_KHR_vulkan_memory_model"
6047 OpMemoryModel Logical VulkanKHR
6048 %1 = OpTypeVoid
6049 %2 = OpTypeInt 32 0
6050 %3 = OpTypePointer Output %2
6051 %4 = OpVariable %3 Output
6052 %5 = OpTypePointer Uniform %2
6053 %6 = OpVariable %5 Uniform
6054 %7 = OpConstant %2 2
6055 %8 = OpConstant %2 5
6056 %9 = OpTypeFunction %1
6057 %10 = OpFunction %1 None %9
6058 %11 = OpLabel
6059 OpCopyMemory %4 %6 NonPrivatePointerKHR
6060 OpReturn
6061 OpFunctionEnd
6062 )";
6063 
6064   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6065   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6066   EXPECT_THAT(getDiagnosticString(),
6067               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
6068                         "Workgroup, CrossWorkgroup, Generic, Image or "
6069                         "StorageBuffer storage classes."));
6070 }
6071 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemoryVisibleBadStorageClass)6072 TEST_F(ValidateIdWithMessage,
6073        VulkanMemoryModelCopyMemoryVisibleBadStorageClass) {
6074   std::string spirv = R"(
6075 OpCapability Shader
6076 OpCapability Linkage
6077 OpCapability VulkanMemoryModelKHR
6078 OpExtension "SPV_KHR_vulkan_memory_model"
6079 OpMemoryModel Logical VulkanKHR
6080 %1 = OpTypeVoid
6081 %2 = OpTypeInt 32 0
6082 %3 = OpTypePointer Workgroup %2
6083 %4 = OpVariable %3 Workgroup
6084 %5 = OpTypePointer Input %2
6085 %6 = OpVariable %5 Input
6086 %7 = OpConstant %2 2
6087 %8 = OpConstant %2 5
6088 %9 = OpTypeFunction %1
6089 %10 = OpFunction %1 None %9
6090 %11 = OpLabel
6091 OpCopyMemory %4 %6 NonPrivatePointerKHR
6092 OpReturn
6093 OpFunctionEnd
6094 )";
6095 
6096   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6097   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6098   EXPECT_THAT(getDiagnosticString(),
6099               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
6100                         "Workgroup, CrossWorkgroup, Generic, Image or "
6101                         "StorageBuffer storage classes."));
6102 }
6103 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedAvailable)6104 TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemorySizedAvailable) {
6105   std::string spirv = R"(
6106 OpCapability Shader
6107 OpCapability Linkage
6108 OpCapability Addresses
6109 OpCapability VulkanMemoryModelKHR
6110 OpExtension "SPV_KHR_vulkan_memory_model"
6111 OpMemoryModel Logical VulkanKHR
6112 %1 = OpTypeVoid
6113 %2 = OpTypeInt 32 0
6114 %3 = OpTypePointer Workgroup %2
6115 %4 = OpVariable %3 Workgroup
6116 %5 = OpTypePointer Uniform %2
6117 %6 = OpVariable %5 Uniform
6118 %7 = OpConstant %2 2
6119 %8 = OpConstant %2 5
6120 %9 = OpTypeFunction %1
6121 %10 = OpFunction %1 None %9
6122 %11 = OpLabel
6123 OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR %7
6124 OpReturn
6125 OpFunctionEnd
6126 )";
6127 
6128   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6129   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6130 }
6131 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedVisible)6132 TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemorySizedVisible) {
6133   std::string spirv = R"(
6134 OpCapability Shader
6135 OpCapability Linkage
6136 OpCapability Addresses
6137 OpCapability VulkanMemoryModelKHR
6138 OpExtension "SPV_KHR_vulkan_memory_model"
6139 OpMemoryModel Logical VulkanKHR
6140 %1 = OpTypeVoid
6141 %2 = OpTypeInt 32 0
6142 %3 = OpTypePointer Workgroup %2
6143 %4 = OpVariable %3 Workgroup
6144 %5 = OpTypePointer Uniform %2
6145 %6 = OpVariable %5 Uniform
6146 %7 = OpConstant %2 2
6147 %8 = OpConstant %2 5
6148 %9 = OpTypeFunction %1
6149 %10 = OpFunction %1 None %9
6150 %11 = OpLabel
6151 OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerVisibleKHR %8
6152 OpReturn
6153 OpFunctionEnd
6154 )";
6155 
6156   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6157   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6158 }
6159 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedAvailableAndVisible)6160 TEST_F(ValidateIdWithMessage,
6161        VulkanMemoryModelCopyMemorySizedAvailableAndVisible) {
6162   std::string spirv = R"(
6163 OpCapability Shader
6164 OpCapability Linkage
6165 OpCapability Addresses
6166 OpCapability VulkanMemoryModelKHR
6167 OpExtension "SPV_KHR_vulkan_memory_model"
6168 OpMemoryModel Logical VulkanKHR
6169 %1 = OpTypeVoid
6170 %2 = OpTypeInt 32 0
6171 %3 = OpTypePointer Workgroup %2
6172 %4 = OpVariable %3 Workgroup
6173 %5 = OpTypePointer Uniform %2
6174 %6 = OpVariable %5 Uniform
6175 %7 = OpConstant %2 2
6176 %8 = OpConstant %2 5
6177 %9 = OpTypeFunction %1
6178 %10 = OpFunction %1 None %9
6179 %11 = OpLabel
6180 OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8
6181 OpReturn
6182 OpFunctionEnd
6183 )";
6184 
6185   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6186   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6187 }
6188 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedAvailableMissingNonPrivatePointer)6189 TEST_F(ValidateIdWithMessage,
6190        VulkanMemoryModelCopyMemorySizedAvailableMissingNonPrivatePointer) {
6191   std::string spirv = R"(
6192 OpCapability Shader
6193 OpCapability Linkage
6194 OpCapability Addresses
6195 OpCapability VulkanMemoryModelKHR
6196 OpExtension "SPV_KHR_vulkan_memory_model"
6197 OpMemoryModel Logical VulkanKHR
6198 %1 = OpTypeVoid
6199 %2 = OpTypeInt 32 0
6200 %3 = OpTypePointer Workgroup %2
6201 %4 = OpVariable %3 Workgroup
6202 %5 = OpTypePointer Uniform %2
6203 %6 = OpVariable %5 Uniform
6204 %7 = OpConstant %2 2
6205 %8 = OpConstant %2 5
6206 %9 = OpTypeFunction %1
6207 %10 = OpFunction %1 None %9
6208 %11 = OpLabel
6209 OpCopyMemorySized %4 %6 %7 MakePointerAvailableKHR %7
6210 OpReturn
6211 OpFunctionEnd
6212 )";
6213 
6214   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6215   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6216   EXPECT_THAT(getDiagnosticString(),
6217               HasSubstr("NonPrivatePointerKHR must be specified if "
6218                         "MakePointerAvailableKHR is specified."));
6219 }
6220 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedVisibleMissingNonPrivatePointer)6221 TEST_F(ValidateIdWithMessage,
6222        VulkanMemoryModelCopyMemorySizedVisibleMissingNonPrivatePointer) {
6223   std::string spirv = R"(
6224 OpCapability Shader
6225 OpCapability Linkage
6226 OpCapability Addresses
6227 OpCapability VulkanMemoryModelKHR
6228 OpExtension "SPV_KHR_vulkan_memory_model"
6229 OpMemoryModel Logical VulkanKHR
6230 %1 = OpTypeVoid
6231 %2 = OpTypeInt 32 0
6232 %3 = OpTypePointer Workgroup %2
6233 %4 = OpVariable %3 Workgroup
6234 %5 = OpTypePointer Uniform %2
6235 %6 = OpVariable %5 Uniform
6236 %7 = OpConstant %2 2
6237 %8 = OpConstant %2 5
6238 %9 = OpTypeFunction %1
6239 %10 = OpFunction %1 None %9
6240 %11 = OpLabel
6241 OpCopyMemorySized %4 %6 %7 MakePointerVisibleKHR %8
6242 OpReturn
6243 OpFunctionEnd
6244 )";
6245 
6246   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6247   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6248   EXPECT_THAT(getDiagnosticString(),
6249               HasSubstr("NonPrivatePointerKHR must be specified if "
6250                         "MakePointerVisibleKHR is specified."));
6251 }
6252 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedAvailableBadStorageClass)6253 TEST_F(ValidateIdWithMessage,
6254        VulkanMemoryModelCopyMemorySizedAvailableBadStorageClass) {
6255   std::string spirv = R"(
6256 OpCapability Shader
6257 OpCapability Linkage
6258 OpCapability Addresses
6259 OpCapability VulkanMemoryModelKHR
6260 OpExtension "SPV_KHR_vulkan_memory_model"
6261 OpMemoryModel Logical VulkanKHR
6262 %1 = OpTypeVoid
6263 %2 = OpTypeInt 32 0
6264 %3 = OpTypePointer Output %2
6265 %4 = OpVariable %3 Output
6266 %5 = OpTypePointer Uniform %2
6267 %6 = OpVariable %5 Uniform
6268 %7 = OpConstant %2 2
6269 %8 = OpConstant %2 5
6270 %9 = OpTypeFunction %1
6271 %10 = OpFunction %1 None %9
6272 %11 = OpLabel
6273 OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR
6274 OpReturn
6275 OpFunctionEnd
6276 )";
6277 
6278   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6279   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6280   EXPECT_THAT(getDiagnosticString(),
6281               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
6282                         "Workgroup, CrossWorkgroup, Generic, Image or "
6283                         "StorageBuffer storage classes."));
6284 }
6285 
TEST_F(ValidateIdWithMessage,VulkanMemoryModelCopyMemorySizedVisibleBadStorageClass)6286 TEST_F(ValidateIdWithMessage,
6287        VulkanMemoryModelCopyMemorySizedVisibleBadStorageClass) {
6288   std::string spirv = R"(
6289 OpCapability Shader
6290 OpCapability Linkage
6291 OpCapability Addresses
6292 OpCapability VulkanMemoryModelKHR
6293 OpExtension "SPV_KHR_vulkan_memory_model"
6294 OpMemoryModel Logical VulkanKHR
6295 %1 = OpTypeVoid
6296 %2 = OpTypeInt 32 0
6297 %3 = OpTypePointer Workgroup %2
6298 %4 = OpVariable %3 Workgroup
6299 %5 = OpTypePointer Input %2
6300 %6 = OpVariable %5 Input
6301 %7 = OpConstant %2 2
6302 %8 = OpConstant %2 5
6303 %9 = OpTypeFunction %1
6304 %10 = OpFunction %1 None %9
6305 %11 = OpLabel
6306 OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR
6307 OpReturn
6308 OpFunctionEnd
6309 )";
6310 
6311   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6312   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6313   EXPECT_THAT(getDiagnosticString(),
6314               HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, "
6315                         "Workgroup, CrossWorkgroup, Generic, Image or "
6316                         "StorageBuffer storage classes."));
6317 }
6318 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock1)6319 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock1) {
6320   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6321 %1 = OpTypeVoid
6322 %2 = OpTypeFunction %1
6323 %3 = OpTypeFloat 32
6324 %4 = OpTypeFunction %3
6325 %5 = OpFunction %1 None %2
6326 %6 = OpLabel
6327 OpReturn
6328 %7 = OpLabel
6329 %8 = OpFunctionCall %3 %9
6330 OpUnreachable
6331 OpFunctionEnd
6332 %9 = OpFunction %3 None %4
6333 %10 = OpLabel
6334 OpReturnValue %8
6335 OpFunctionEnd
6336 )";
6337 
6338   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6339   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6340   EXPECT_THAT(getDiagnosticString(),
6341               HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its "
6342                         "use in block 10[%10]\n  %10 = OpLabel"));
6343 }
6344 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock2)6345 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock2) {
6346   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6347 %1 = OpTypeVoid
6348 %2 = OpTypeFunction %1
6349 %3 = OpTypeFloat 32
6350 %4 = OpTypeFunction %3
6351 %5 = OpFunction %1 None %2
6352 %6 = OpLabel
6353 OpReturn
6354 %7 = OpLabel
6355 %8 = OpFunctionCall %3 %9
6356 OpUnreachable
6357 OpFunctionEnd
6358 %9 = OpFunction %3 None %4
6359 %10 = OpLabel
6360 OpReturnValue %8
6361 OpFunctionEnd
6362 )";
6363 
6364   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6365   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6366   EXPECT_THAT(getDiagnosticString(),
6367               HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its "
6368                         "use in block 10[%10]\n  %10 = OpLabel"));
6369 }
6370 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock3)6371 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock3) {
6372   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6373 %1 = OpTypeVoid
6374 %2 = OpTypeFunction %1
6375 %3 = OpTypeFloat 32
6376 %4 = OpTypeFunction %3
6377 %5 = OpFunction %1 None %2
6378 %6 = OpLabel
6379 OpReturn
6380 %7 = OpLabel
6381 %8 = OpFunctionCall %3 %9
6382 OpReturn
6383 OpFunctionEnd
6384 %9 = OpFunction %3 None %4
6385 %10 = OpLabel
6386 OpReturnValue %8
6387 OpFunctionEnd
6388 )";
6389 
6390   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6391   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6392   EXPECT_THAT(getDiagnosticString(),
6393               HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its "
6394                         "use in block 10[%10]\n  %10 = OpLabel"));
6395 }
6396 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock4)6397 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock4) {
6398   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6399 %1 = OpTypeVoid
6400 %2 = OpTypeFunction %1
6401 %3 = OpTypeFloat 32
6402 %4 = OpTypeFunction %3
6403 %5 = OpFunction %1 None %2
6404 %6 = OpLabel
6405 OpReturn
6406 %7 = OpLabel
6407 %8 = OpUndef %3
6408 %9 = OpCopyObject %3 %8
6409 OpReturn
6410 OpFunctionEnd
6411 )";
6412 
6413   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6414   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6415 }
6416 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock5)6417 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock5) {
6418   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6419 %1 = OpTypeVoid
6420 %2 = OpTypeFunction %1
6421 %3 = OpTypeFloat 32
6422 %4 = OpTypeFunction %3
6423 %5 = OpFunction %1 None %2
6424 %6 = OpLabel
6425 OpReturn
6426 %7 = OpLabel
6427 %8 = OpUndef %3
6428 OpBranch %9
6429 %9 = OpLabel
6430 %10 = OpCopyObject %3 %8
6431 OpReturn
6432 OpFunctionEnd
6433 )";
6434 
6435   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6436   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6437 }
6438 
TEST_F(ValidateIdWithMessage,IdDefInUnreachableBlock6)6439 TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock6) {
6440   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6441 %1 = OpTypeVoid
6442 %2 = OpTypeFunction %1
6443 %3 = OpTypeFloat 32
6444 %4 = OpTypeFunction %3
6445 %5 = OpFunction %1 None %2
6446 %6 = OpLabel
6447 OpBranch %7
6448 %8 = OpLabel
6449 %9 = OpUndef %3
6450 OpBranch %7
6451 %7 = OpLabel
6452 %10 = OpCopyObject %3 %9
6453 OpReturn
6454 OpFunctionEnd
6455 )";
6456 
6457   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6458   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6459   EXPECT_THAT(getDiagnosticString(),
6460               HasSubstr("ID 9[%9] defined in block 8[%8] does not dominate its "
6461                         "use in block 7[%7]\n  %7 = OpLabel"));
6462 }
6463 
TEST_F(ValidateIdWithMessage,ReachableDefUnreachableUse)6464 TEST_F(ValidateIdWithMessage, ReachableDefUnreachableUse) {
6465   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6466 %1 = OpTypeVoid
6467 %2 = OpTypeFunction %1
6468 %3 = OpTypeFloat 32
6469 %4 = OpTypeFunction %3
6470 %5 = OpFunction %1 None %2
6471 %6 = OpLabel
6472 %7 = OpUndef %3
6473 OpReturn
6474 %8 = OpLabel
6475 %9 = OpCopyObject %3 %7
6476 OpReturn
6477 OpFunctionEnd
6478 )";
6479 
6480   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6481   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6482 }
6483 
TEST_F(ValidateIdWithMessage,UnreachableDefUsedInPhi)6484 TEST_F(ValidateIdWithMessage, UnreachableDefUsedInPhi) {
6485   const std::string spirv = kNoKernelGLSL450MemoryModel + R"(
6486        %void = OpTypeVoid
6487           %3 = OpTypeFunction %void
6488       %float = OpTypeFloat 32
6489        %bool = OpTypeBool
6490           %6 = OpTypeFunction %float
6491           %1 = OpFunction %void None %3
6492           %7 = OpLabel
6493           %8 = OpUndef %bool
6494                OpSelectionMerge %9 None
6495                OpBranchConditional %8 %10 %9
6496          %10 = OpLabel
6497          %11 = OpUndef %float
6498                OpBranch %9
6499          %12 = OpLabel
6500          %13 = OpUndef %float
6501                OpUnreachable
6502           %9 = OpLabel
6503          %14 = OpPhi %float %11 %10 %13 %7
6504                OpReturn
6505                OpFunctionEnd
6506 )";
6507 
6508   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6509   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6510   EXPECT_THAT(
6511       getDiagnosticString(),
6512       HasSubstr("In OpPhi instruction 14[%14], ID 13[%13] definition does not "
6513                 "dominate its parent 7[%7]\n  %14 = OpPhi %float %11 %10 %13 "
6514                 "%7"));
6515 }
6516 
TEST_F(ValidateIdWithMessage,OpTypeForwardPointerNotAPointerType)6517 TEST_F(ValidateIdWithMessage, OpTypeForwardPointerNotAPointerType) {
6518   std::string spirv = R"(
6519      OpCapability GenericPointer
6520      OpCapability VariablePointersStorageBuffer
6521      OpMemoryModel Logical GLSL450
6522      OpEntryPoint Fragment %1 "main"
6523      OpExecutionMode %1 OriginLowerLeft
6524      OpTypeForwardPointer %2 CrossWorkgroup
6525 %2 = OpTypeVoid
6526 %3 = OpTypeFunction %2
6527 %1 = OpFunction %2 DontInline %3
6528 %4 = OpLabel
6529      OpReturn
6530      OpFunctionEnd
6531 )";
6532 
6533   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6534   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6535   EXPECT_THAT(getDiagnosticString(),
6536               HasSubstr("Pointer type in OpTypeForwardPointer is not a pointer "
6537                         "type.\n  OpTypeForwardPointer %void CrossWorkgroup"));
6538 }
6539 
TEST_F(ValidateIdWithMessage,OpTypeForwardPointerWrongStorageClass)6540 TEST_F(ValidateIdWithMessage, OpTypeForwardPointerWrongStorageClass) {
6541   std::string spirv = R"(
6542      OpCapability GenericPointer
6543      OpCapability VariablePointersStorageBuffer
6544      OpMemoryModel Logical GLSL450
6545      OpEntryPoint Fragment %1 "main"
6546      OpExecutionMode %1 OriginLowerLeft
6547      OpTypeForwardPointer %2 CrossWorkgroup
6548 %int = OpTypeInt 32 1
6549 %2 = OpTypePointer Function %int
6550 %void = OpTypeVoid
6551 %3 = OpTypeFunction %void
6552 %1 = OpFunction %void None %3
6553 %4 = OpLabel
6554      OpReturn
6555      OpFunctionEnd
6556 )";
6557 
6558   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
6559   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
6560   EXPECT_THAT(
6561       getDiagnosticString(),
6562       HasSubstr("Storage class in OpTypeForwardPointer does not match the "
6563                 "pointer definition.\n  OpTypeForwardPointer "
6564                 "%_ptr_Function_int CrossWorkgroup"));
6565 }
6566 
TEST_F(ValidateIdWithMessage,MissingForwardPointer)6567 TEST_F(ValidateIdWithMessage, MissingForwardPointer) {
6568   const std::string spirv = R"(
6569                OpCapability Linkage
6570                OpCapability Shader
6571                OpMemoryModel Logical Simple
6572       %float = OpTypeFloat 32
6573   %_struct_9 = OpTypeStruct %float %_ptr_Uniform__struct_9
6574 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
6575        %1278 = OpVariable %_ptr_Uniform__struct_9 Uniform
6576 )";
6577 
6578   CompileSuccessfully(spirv);
6579   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
6580   EXPECT_THAT(
6581       getDiagnosticString(),
6582       HasSubstr(
6583           "Operand 3[%_ptr_Uniform__struct_2] requires a previous definition"));
6584 }
6585 
6586 }  // namespace
6587 }  // namespace val
6588 }  // namespace spvtools
6589