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 // Validation tests for OpVariable storage class
16 
17 #include <sstream>
18 #include <string>
19 #include <tuple>
20 
21 #include "gmock/gmock.h"
22 #include "test/val/val_fixtures.h"
23 
24 namespace spvtools {
25 namespace val {
26 namespace {
27 
28 using ::testing::HasSubstr;
29 using ::testing::Values;
30 using ValidateStorage = spvtest::ValidateBase<std::string>;
31 using ValidateStorageExecutionModel = spvtest::ValidateBase<std::string>;
32 
TEST_F(ValidateStorage,FunctionStorageInsideFunction)33 TEST_F(ValidateStorage, FunctionStorageInsideFunction) {
34   char str[] = R"(
35           OpCapability Shader
36           OpCapability Linkage
37           OpMemoryModel Logical GLSL450
38 %intt   = OpTypeInt 32 1
39 %voidt  = OpTypeVoid
40 %vfunct = OpTypeFunction %voidt
41 %ptrt   = OpTypePointer Function %intt
42 %func   = OpFunction %voidt None %vfunct
43 %funcl  = OpLabel
44 %var    = OpVariable %ptrt Function
45           OpReturn
46           OpFunctionEnd
47 )";
48 
49   CompileSuccessfully(str);
50   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
51 }
52 
TEST_F(ValidateStorage,FunctionStorageOutsideFunction)53 TEST_F(ValidateStorage, FunctionStorageOutsideFunction) {
54   char str[] = R"(
55           OpCapability Shader
56           OpCapability Linkage
57           OpMemoryModel Logical GLSL450
58 %intt   = OpTypeInt 32 1
59 %voidt  = OpTypeVoid
60 %vfunct = OpTypeFunction %voidt
61 %ptrt   = OpTypePointer Function %intt
62 %var    = OpVariable %ptrt Function
63 %func   = OpFunction %voidt None %vfunct
64 %funcl  = OpLabel
65           OpReturn
66           OpFunctionEnd
67 )";
68 
69   CompileSuccessfully(str);
70   ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
71   EXPECT_THAT(getDiagnosticString(),
72               HasSubstr("Variables can not have a function[7] storage class "
73                         "outside of a function"));
74 }
75 
TEST_F(ValidateStorage,OtherStorageOutsideFunction)76 TEST_F(ValidateStorage, OtherStorageOutsideFunction) {
77   char str[] = R"(
78               OpCapability Shader
79               OpCapability Kernel
80               OpCapability AtomicStorage
81               OpCapability Linkage
82               OpMemoryModel Logical GLSL450
83 %intt       = OpTypeInt 32 0
84 %voidt      = OpTypeVoid
85 %vfunct     = OpTypeFunction %voidt
86 %uniconptrt = OpTypePointer UniformConstant %intt
87 %unicon     = OpVariable %uniconptrt UniformConstant
88 %inputptrt  = OpTypePointer Input %intt
89 %input      = OpVariable %inputptrt Input
90 %unifptrt   = OpTypePointer Uniform %intt
91 %unif       = OpVariable %unifptrt Uniform
92 %outputptrt = OpTypePointer Output %intt
93 %output     = OpVariable %outputptrt Output
94 %wgroupptrt = OpTypePointer Workgroup %intt
95 %wgroup     = OpVariable %wgroupptrt Workgroup
96 %xwgrpptrt  = OpTypePointer CrossWorkgroup %intt
97 %xwgrp      = OpVariable %xwgrpptrt CrossWorkgroup
98 %privptrt   = OpTypePointer Private %intt
99 %priv       = OpVariable %privptrt Private
100 %pushcoptrt = OpTypePointer PushConstant %intt
101 %pushco     = OpVariable %pushcoptrt PushConstant
102 %atomcptrt  = OpTypePointer AtomicCounter %intt
103 %atomct     = OpVariable %atomcptrt AtomicCounter
104 %imageptrt  = OpTypePointer Image %intt
105 %image      = OpVariable %imageptrt Image
106 %func       = OpFunction %voidt None %vfunct
107 %funcl      = OpLabel
108               OpReturn
109               OpFunctionEnd
110 )";
111 
112   CompileSuccessfully(str);
113   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
114 }
115 
116 // clang-format off
TEST_P(ValidateStorage,OtherStorageInsideFunction)117 TEST_P(ValidateStorage, OtherStorageInsideFunction) {
118   std::stringstream ss;
119   ss << R"(
120           OpCapability Shader
121           OpCapability Kernel
122           OpCapability AtomicStorage
123           OpCapability Linkage
124           OpMemoryModel Logical GLSL450
125 %intt   = OpTypeInt 32 0
126 %voidt  = OpTypeVoid
127 %vfunct = OpTypeFunction %voidt
128 %ptrt   = OpTypePointer Function %intt
129 %func   = OpFunction %voidt None %vfunct
130 %funcl  = OpLabel
131 %var    = OpVariable %ptrt )" << GetParam() << R"(
132           OpReturn
133           OpFunctionEnd
134 )";
135 
136   CompileSuccessfully(ss.str());
137   ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
138   EXPECT_THAT(getDiagnosticString(), HasSubstr(
139       "Variables must have a function[7] storage class inside of a function"));
140 }
141 
142 INSTANTIATE_TEST_SUITE_P(MatrixOp, ValidateStorage,
143                         ::testing::Values(
144                              "Input",
145                              "Uniform",
146                              "Output",
147                              "Workgroup",
148                              "CrossWorkgroup",
149                              "Private",
150                              "PushConstant",
151                              "AtomicCounter",
152                              "Image"));
153 // clang-format on
154 
TEST_F(ValidateStorage,GenericVariableOutsideFunction)155 TEST_F(ValidateStorage, GenericVariableOutsideFunction) {
156   const auto str = R"(
157           OpCapability Kernel
158           OpCapability Linkage
159           OpCapability GenericPointer
160           OpMemoryModel Logical OpenCL
161 %intt   = OpTypeInt 32 0
162 %ptrt   = OpTypePointer Function %intt
163 %var    = OpVariable %ptrt Generic
164 )";
165   CompileSuccessfully(str);
166   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
167   EXPECT_THAT(getDiagnosticString(),
168               HasSubstr("OpVariable storage class cannot be Generic"));
169 }
170 
TEST_F(ValidateStorage,GenericVariableInsideFunction)171 TEST_F(ValidateStorage, GenericVariableInsideFunction) {
172   const auto str = R"(
173           OpCapability Shader
174           OpCapability Linkage
175           OpCapability GenericPointer
176           OpMemoryModel Logical GLSL450
177 %intt   = OpTypeInt 32 1
178 %voidt  = OpTypeVoid
179 %vfunct = OpTypeFunction %voidt
180 %ptrt   = OpTypePointer Function %intt
181 %func   = OpFunction %voidt None %vfunct
182 %funcl  = OpLabel
183 %var    = OpVariable %ptrt Generic
184           OpReturn
185           OpFunctionEnd
186 )";
187   CompileSuccessfully(str);
188   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
189   EXPECT_THAT(getDiagnosticString(),
190               HasSubstr("OpVariable storage class cannot be Generic"));
191 }
192 
TEST_F(ValidateStorage,RelaxedLogicalPointerFunctionParam)193 TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParam) {
194   const auto str = R"(
195           OpCapability Shader
196           OpCapability Linkage
197           OpMemoryModel Logical GLSL450
198 %intt   = OpTypeInt 32 1
199 %voidt  = OpTypeVoid
200 %ptrt   = OpTypePointer Function %intt
201 %vfunct = OpTypeFunction %voidt
202 %vifunct = OpTypeFunction %voidt %ptrt
203 %wgroupptrt = OpTypePointer Workgroup %intt
204 %wgroup = OpVariable %wgroupptrt Workgroup
205 %main   = OpFunction %voidt None %vfunct
206 %mainl  = OpLabel
207 %ret    = OpFunctionCall %voidt %func %wgroup
208           OpReturn
209           OpFunctionEnd
210 %func   = OpFunction %voidt None %vifunct
211 %arg    = OpFunctionParameter %ptrt
212 %funcl  = OpLabel
213           OpReturn
214           OpFunctionEnd
215 )";
216   CompileSuccessfully(str);
217   getValidatorOptions()->before_hlsl_legalization = true;
218   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
219 }
220 
TEST_F(ValidateStorage,RelaxedLogicalPointerFunctionParamBad)221 TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) {
222   const auto str = R"(
223           OpCapability Shader
224           OpCapability Linkage
225           OpMemoryModel Logical GLSL450
226 %floatt = OpTypeFloat 32
227 %intt   = OpTypeInt 32 1
228 %voidt  = OpTypeVoid
229 %ptrt   = OpTypePointer Function %intt
230 %vfunct = OpTypeFunction %voidt
231 %vifunct = OpTypeFunction %voidt %ptrt
232 %wgroupptrt = OpTypePointer Workgroup %floatt
233 %wgroup = OpVariable %wgroupptrt Workgroup
234 %main   = OpFunction %voidt None %vfunct
235 %mainl  = OpLabel
236 %ret    = OpFunctionCall %voidt %func %wgroup
237           OpReturn
238           OpFunctionEnd
239 %func   = OpFunction %voidt None %vifunct
240 %arg    = OpFunctionParameter %ptrt
241 %funcl  = OpLabel
242           OpReturn
243           OpFunctionEnd
244 )";
245   CompileSuccessfully(str);
246   getValidatorOptions()->relax_logical_pointer = true;
247   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
248   EXPECT_THAT(getDiagnosticString(),
249               HasSubstr("OpFunctionCall Argument <id> '"));
250 }
251 
GenerateExecutionModelCode(const std::string & execution_model,const std::string & storage_class,bool store)252 std::string GenerateExecutionModelCode(const std::string& execution_model,
253                                        const std::string& storage_class,
254                                        bool store) {
255   const std::string mode = (execution_model.compare("GLCompute") == 0)
256                                ? "OpExecutionMode %func LocalSize 1 1 1"
257                                : "";
258   const std::string operation =
259       (store) ? "OpStore %var %int0" : "%load = OpLoad %intt %var";
260   std::ostringstream ss;
261   ss << R"(
262               OpCapability Shader
263               OpCapability RayTracingKHR
264               OpExtension "SPV_KHR_ray_tracing"
265               OpMemoryModel Logical GLSL450
266               OpEntryPoint )"
267      << execution_model << R"( %func "func" %var
268               )" << mode << R"(
269               OpDecorate %var Location 0
270 %intt       = OpTypeInt 32 0
271 %int0       = OpConstant %intt 0
272 %voidt      = OpTypeVoid
273 %vfunct     = OpTypeFunction %voidt
274 %ptr        = OpTypePointer )"
275      << storage_class << R"( %intt
276 %var        = OpVariable %ptr )" << storage_class << R"(
277 %func       = OpFunction %voidt None %vfunct
278 %funcl      = OpLabel
279               )" << operation << R"(
280               OpReturn
281               OpFunctionEnd
282 )";
283 
284   return ss.str();
285 }
286 
TEST_P(ValidateStorageExecutionModel,VulkanOutsideStoreFailure)287 TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
288   std::string execution_model = GetParam();
289   CompileSuccessfully(
290       GenerateExecutionModelCode(execution_model, "Output", true).c_str(),
291       SPV_ENV_VULKAN_1_0);
292   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
293   EXPECT_THAT(getDiagnosticString(),
294               AnyVUID("VUID-StandaloneSpirv-None-04644"));
295   EXPECT_THAT(
296       getDiagnosticString(),
297       HasSubstr("in Vulkan environment, Output Storage Class must not be used "
298                 "in GLCompute, RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
299                 "ClosestHitKHR, MissKHR, or CallableKHR execution models"));
300 }
301 
TEST_P(ValidateStorageExecutionModel,CallableDataStore)302 TEST_P(ValidateStorageExecutionModel, CallableDataStore) {
303   std::string execution_model = GetParam();
304   CompileSuccessfully(
305       GenerateExecutionModelCode(execution_model, "CallableDataKHR", true)
306           .c_str(),
307       SPV_ENV_VULKAN_1_2);
308   if (execution_model.compare("RayGenerationKHR") == 0 ||
309       execution_model.compare("ClosestHitKHR") == 0 ||
310       execution_model.compare("CallableKHR") == 0 ||
311       execution_model.compare("MissKHR") == 0) {
312     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
313   } else {
314     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
315     EXPECT_THAT(getDiagnosticString(),
316                 AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
317     EXPECT_THAT(
318         getDiagnosticString(),
319         HasSubstr(
320             "CallableDataKHR Storage Class is limited to RayGenerationKHR, "
321             "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
322   }
323 }
324 
TEST_P(ValidateStorageExecutionModel,CallableDataLoad)325 TEST_P(ValidateStorageExecutionModel, CallableDataLoad) {
326   std::string execution_model = GetParam();
327   CompileSuccessfully(
328       GenerateExecutionModelCode(execution_model, "CallableDataKHR", false)
329           .c_str(),
330       SPV_ENV_VULKAN_1_2);
331   if (execution_model.compare("RayGenerationKHR") == 0 ||
332       execution_model.compare("ClosestHitKHR") == 0 ||
333       execution_model.compare("CallableKHR") == 0 ||
334       execution_model.compare("MissKHR") == 0) {
335     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
336   } else {
337     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
338     EXPECT_THAT(getDiagnosticString(),
339                 AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
340     EXPECT_THAT(
341         getDiagnosticString(),
342         HasSubstr(
343             "CallableDataKHR Storage Class is limited to RayGenerationKHR, "
344             "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
345   }
346 }
347 
TEST_P(ValidateStorageExecutionModel,IncomingCallableDataStore)348 TEST_P(ValidateStorageExecutionModel, IncomingCallableDataStore) {
349   std::string execution_model = GetParam();
350   CompileSuccessfully(GenerateExecutionModelCode(
351                           execution_model, "IncomingCallableDataKHR", true)
352                           .c_str(),
353                       SPV_ENV_VULKAN_1_2);
354   if (execution_model.compare("CallableKHR") == 0) {
355     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
356   } else {
357     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
358     EXPECT_THAT(getDiagnosticString(),
359                 AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
360     EXPECT_THAT(getDiagnosticString(),
361                 HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
362                           "CallableKHR execution model"));
363   }
364 }
365 
TEST_P(ValidateStorageExecutionModel,IncomingCallableDataLoad)366 TEST_P(ValidateStorageExecutionModel, IncomingCallableDataLoad) {
367   std::string execution_model = GetParam();
368   CompileSuccessfully(GenerateExecutionModelCode(
369                           execution_model, "IncomingCallableDataKHR", false)
370                           .c_str(),
371                       SPV_ENV_VULKAN_1_2);
372   if (execution_model.compare("CallableKHR") == 0) {
373     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
374   } else {
375     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
376     EXPECT_THAT(getDiagnosticString(),
377                 AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
378     EXPECT_THAT(getDiagnosticString(),
379                 HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
380                           "CallableKHR execution model"));
381   }
382 }
383 
TEST_P(ValidateStorageExecutionModel,RayPayloadStore)384 TEST_P(ValidateStorageExecutionModel, RayPayloadStore) {
385   std::string execution_model = GetParam();
386   CompileSuccessfully(
387       GenerateExecutionModelCode(execution_model, "RayPayloadKHR", true)
388           .c_str(),
389       SPV_ENV_VULKAN_1_2);
390   if (execution_model.compare("RayGenerationKHR") == 0 ||
391       execution_model.compare("ClosestHitKHR") == 0 ||
392       execution_model.compare("MissKHR") == 0) {
393     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
394   } else {
395     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
396     EXPECT_THAT(getDiagnosticString(),
397                 AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
398     EXPECT_THAT(
399         getDiagnosticString(),
400         HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
401                   "ClosestHitKHR, and MissKHR execution model"));
402   }
403 }
404 
TEST_P(ValidateStorageExecutionModel,RayPayloadLoad)405 TEST_P(ValidateStorageExecutionModel, RayPayloadLoad) {
406   std::string execution_model = GetParam();
407   CompileSuccessfully(
408       GenerateExecutionModelCode(execution_model, "RayPayloadKHR", false)
409           .c_str(),
410       SPV_ENV_VULKAN_1_2);
411   if (execution_model.compare("RayGenerationKHR") == 0 ||
412       execution_model.compare("ClosestHitKHR") == 0 ||
413       execution_model.compare("MissKHR") == 0) {
414     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
415   } else {
416     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
417     EXPECT_THAT(getDiagnosticString(),
418                 AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
419     EXPECT_THAT(
420         getDiagnosticString(),
421         HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
422                   "ClosestHitKHR, and MissKHR execution model"));
423   }
424 }
425 
TEST_P(ValidateStorageExecutionModel,HitAttributeStore)426 TEST_P(ValidateStorageExecutionModel, HitAttributeStore) {
427   std::string execution_model = GetParam();
428   CompileSuccessfully(
429       GenerateExecutionModelCode(execution_model, "HitAttributeKHR", true)
430           .c_str(),
431       SPV_ENV_VULKAN_1_2);
432   if (execution_model.compare("IntersectionKHR") == 0) {
433     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
434   } else if (execution_model.compare("AnyHitKHR") == 0 ||
435              execution_model.compare("ClosestHitKHR") == 0) {
436     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
437     EXPECT_THAT(getDiagnosticString(),
438                 AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04703"));
439     EXPECT_THAT(getDiagnosticString(),
440                 HasSubstr("HitAttributeKHR Storage Class variables are read "
441                           "only with AnyHitKHR and ClosestHitKHR"));
442   } else {
443     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
444     EXPECT_THAT(getDiagnosticString(),
445                 AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
446     EXPECT_THAT(
447         getDiagnosticString(),
448         HasSubstr(
449             "HitAttributeKHR Storage Class is limited to IntersectionKHR, "
450             "AnyHitKHR, sand ClosestHitKHR execution model"));
451   }
452 }
453 
TEST_P(ValidateStorageExecutionModel,HitAttributeLoad)454 TEST_P(ValidateStorageExecutionModel, HitAttributeLoad) {
455   std::string execution_model = GetParam();
456   CompileSuccessfully(
457       GenerateExecutionModelCode(execution_model, "HitAttributeKHR", false)
458           .c_str(),
459       SPV_ENV_VULKAN_1_2);
460   if (execution_model.compare("IntersectionKHR") == 0 ||
461       execution_model.compare("AnyHitKHR") == 0 ||
462       execution_model.compare("ClosestHitKHR") == 0) {
463     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
464   } else {
465     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
466     EXPECT_THAT(getDiagnosticString(),
467                 AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
468     EXPECT_THAT(
469         getDiagnosticString(),
470         HasSubstr(
471             "HitAttributeKHR Storage Class is limited to IntersectionKHR, "
472             "AnyHitKHR, sand ClosestHitKHR execution model"));
473   }
474 }
475 
TEST_P(ValidateStorageExecutionModel,IncomingRayPayloadStore)476 TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadStore) {
477   std::string execution_model = GetParam();
478   CompileSuccessfully(
479       GenerateExecutionModelCode(execution_model, "IncomingRayPayloadKHR", true)
480           .c_str(),
481       SPV_ENV_VULKAN_1_2);
482   if (execution_model.compare("AnyHitKHR") == 0 ||
483       execution_model.compare("ClosestHitKHR") == 0 ||
484       execution_model.compare("MissKHR") == 0) {
485     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
486   } else {
487     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
488     EXPECT_THAT(getDiagnosticString(),
489                 AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
490     EXPECT_THAT(
491         getDiagnosticString(),
492         HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
493                   "AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
494   }
495 }
496 
TEST_P(ValidateStorageExecutionModel,IncomingRayPayloadLoad)497 TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadLoad) {
498   std::string execution_model = GetParam();
499   CompileSuccessfully(GenerateExecutionModelCode(execution_model,
500                                                  "IncomingRayPayloadKHR", false)
501                           .c_str(),
502                       SPV_ENV_VULKAN_1_2);
503   if (execution_model.compare("AnyHitKHR") == 0 ||
504       execution_model.compare("ClosestHitKHR") == 0 ||
505       execution_model.compare("MissKHR") == 0) {
506     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
507   } else {
508     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
509     EXPECT_THAT(getDiagnosticString(),
510                 AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
511     EXPECT_THAT(
512         getDiagnosticString(),
513         HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
514                   "AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
515   }
516 }
517 
TEST_P(ValidateStorageExecutionModel,ShaderRecordBufferStore)518 TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferStore) {
519   std::string execution_model = GetParam();
520   CompileSuccessfully(
521       GenerateExecutionModelCode(execution_model, "ShaderRecordBufferKHR", true)
522           .c_str(),
523       SPV_ENV_VULKAN_1_2);
524   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
525   EXPECT_THAT(
526       getDiagnosticString(),
527       HasSubstr("ShaderRecordBufferKHR Storage Class variables are read only"));
528 }
529 
TEST_P(ValidateStorageExecutionModel,ShaderRecordBufferLoad)530 TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferLoad) {
531   std::string execution_model = GetParam();
532   CompileSuccessfully(GenerateExecutionModelCode(execution_model,
533                                                  "ShaderRecordBufferKHR", false)
534                           .c_str(),
535                       SPV_ENV_VULKAN_1_2);
536   if (execution_model.compare("RayGenerationKHR") == 0 ||
537       execution_model.compare("IntersectionKHR") == 0 ||
538       execution_model.compare("AnyHitKHR") == 0 ||
539       execution_model.compare("ClosestHitKHR") == 0 ||
540       execution_model.compare("CallableKHR") == 0 ||
541       execution_model.compare("MissKHR") == 0) {
542     ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
543   } else {
544     ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
545     EXPECT_THAT(getDiagnosticString(),
546                 AnyVUID("VUID-StandaloneSpirv-ShaderRecordBufferKHR-07119"));
547     EXPECT_THAT(
548         getDiagnosticString(),
549         HasSubstr("ShaderRecordBufferKHR Storage Class is limited to "
550                   "RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
551                   "ClosestHitKHR, CallableKHR, and MissKHR execution model"));
552   }
553 }
554 
555 INSTANTIATE_TEST_SUITE_P(MatrixExecutionModel, ValidateStorageExecutionModel,
556                          ::testing::Values("RayGenerationKHR",
557                                            "IntersectionKHR", "AnyHitKHR",
558                                            "ClosestHitKHR", "MissKHR",
559                                            "CallableKHR", "GLCompute"));
560 
561 }  // namespace
562 }  // namespace val
563 }  // namespace spvtools
564