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