• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2018 Google LLC.
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 "source/spirv_target_env.h"
21 #include "test/test_fixture.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24 
25 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::Combine;
30 using ::testing::HasSubstr;
31 using ::testing::Values;
32 using ::testing::ValuesIn;
33 
34 using ValidateMode = spvtest::ValidateBase<bool>;
35 
36 const std::string kVoidFunction = R"(%void = OpTypeVoid
37 %void_fn = OpTypeFunction %void
38 %main = OpFunction %void None %void_fn
39 %entry = OpLabel
40 OpReturn
41 OpFunctionEnd
42 )";
43 
TEST_F(ValidateMode,GLComputeNoMode)44 TEST_F(ValidateMode, GLComputeNoMode) {
45   const std::string spirv = R"(
46 OpCapability Shader
47 OpMemoryModel Logical GLSL450
48 OpEntryPoint GLCompute %main "main"
49 )" + kVoidFunction;
50 
51   CompileSuccessfully(spirv);
52   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
53 }
54 
TEST_F(ValidateMode,GLComputeNoModeVulkan)55 TEST_F(ValidateMode, GLComputeNoModeVulkan) {
56   const std::string spirv = R"(
57 OpCapability Shader
58 OpMemoryModel Logical GLSL450
59 OpEntryPoint GLCompute %main "main"
60 )" + kVoidFunction;
61 
62   spv_target_env env = SPV_ENV_VULKAN_1_0;
63   CompileSuccessfully(spirv, env);
64   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
65   EXPECT_THAT(getDiagnosticString(),
66               AnyVUID("VUID-StandaloneSpirv-LocalSize-06426"));
67   EXPECT_THAT(
68       getDiagnosticString(),
69       HasSubstr(
70           "In the Vulkan environment, GLCompute execution model entry "
71           "points require either the LocalSize or LocalSizeId execution mode "
72           "or an object decorated with WorkgroupSize must be specified."));
73 }
74 
TEST_F(ValidateMode,GLComputeNoModeVulkanWorkgroupSize)75 TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
76   const std::string spirv = R"(
77 OpCapability Shader
78 OpMemoryModel Logical GLSL450
79 OpEntryPoint GLCompute %main "main"
80 OpDecorate %int3_1 BuiltIn WorkgroupSize
81 %int = OpTypeInt 32 0
82 %int3 = OpTypeVector %int 3
83 %int_1 = OpConstant %int 1
84 %int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
85 )" + kVoidFunction;
86 
87   spv_target_env env = SPV_ENV_VULKAN_1_0;
88   CompileSuccessfully(spirv, env);
89   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
90 }
91 
TEST_F(ValidateMode,GLComputeVulkanLocalSize)92 TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
93   const std::string spirv = R"(
94 OpCapability Shader
95 OpMemoryModel Logical GLSL450
96 OpEntryPoint GLCompute %main "main"
97 OpExecutionMode %main LocalSize 1 1 1
98 )" + kVoidFunction;
99 
100   spv_target_env env = SPV_ENV_VULKAN_1_0;
101   CompileSuccessfully(spirv, env);
102   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
103 }
104 
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdBad)105 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdBad) {
106   const std::string spirv = R"(
107 OpCapability Shader
108 OpMemoryModel Logical GLSL450
109 OpEntryPoint GLCompute %main "main"
110 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
111 %int = OpTypeInt 32 0
112 %int_1 = OpConstant %int 1
113 )" + kVoidFunction;
114 
115   spv_target_env env = SPV_ENV_VULKAN_1_1;  // need SPIR-V 1.2
116   CompileSuccessfully(spirv, env);
117   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
118   EXPECT_THAT(
119       getDiagnosticString(),
120       HasSubstr("LocalSizeId mode is not allowed by the current environment."));
121 }
122 
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdGood)123 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdGood) {
124   const std::string spirv = R"(
125 OpCapability Shader
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint GLCompute %main "main"
128 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
129 %int = OpTypeInt 32 0
130 %int_1 = OpConstant %int 1
131 )" + kVoidFunction;
132 
133   spv_target_env env = SPV_ENV_VULKAN_1_1;  // need SPIR-V 1.2
134   CompileSuccessfully(spirv, env);
135   spvValidatorOptionsSetAllowLocalSizeId(getValidatorOptions(), true);
136   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
137 }
138 
TEST_F(ValidateMode,FragmentOriginLowerLeftVulkan)139 TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
140   const std::string spirv = R"(
141 OpCapability Shader
142 OpMemoryModel Logical GLSL450
143 OpEntryPoint Fragment %main "main"
144 OpExecutionMode %main OriginLowerLeft
145 )" + kVoidFunction;
146 
147   spv_target_env env = SPV_ENV_VULKAN_1_0;
148   CompileSuccessfully(spirv, env);
149   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
150   EXPECT_THAT(getDiagnosticString(),
151               AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653"));
152   EXPECT_THAT(getDiagnosticString(),
153               HasSubstr("In the Vulkan environment, the OriginLowerLeft "
154                         "execution mode must not be used."));
155 }
156 
TEST_F(ValidateMode,FragmentPixelCenterIntegerVulkan)157 TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
158   const std::string spirv = R"(
159 OpCapability Shader
160 OpMemoryModel Logical GLSL450
161 OpEntryPoint Fragment %main "main"
162 OpExecutionMode %main OriginUpperLeft
163 OpExecutionMode %main PixelCenterInteger
164 )" + kVoidFunction;
165 
166   spv_target_env env = SPV_ENV_VULKAN_1_0;
167   CompileSuccessfully(spirv, env);
168   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
169   EXPECT_THAT(getDiagnosticString(),
170               AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654"));
171   EXPECT_THAT(getDiagnosticString(),
172               HasSubstr("In the Vulkan environment, the PixelCenterInteger "
173                         "execution mode must not be used."));
174 }
175 
TEST_F(ValidateMode,GeometryNoOutputMode)176 TEST_F(ValidateMode, GeometryNoOutputMode) {
177   const std::string spirv = R"(
178 OpCapability Geometry
179 OpMemoryModel Logical GLSL450
180 OpEntryPoint Geometry %main "main"
181 OpExecutionMode %main InputPoints
182 )" + kVoidFunction;
183 
184   CompileSuccessfully(spirv);
185   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
186   EXPECT_THAT(getDiagnosticString(),
187               HasSubstr("Geometry execution model entry points must specify "
188                         "exactly one of OutputPoints, OutputLineStrip or "
189                         "OutputTriangleStrip execution modes."));
190 }
191 
TEST_F(ValidateMode,GeometryNoInputMode)192 TEST_F(ValidateMode, GeometryNoInputMode) {
193   const std::string spirv = R"(
194 OpCapability Geometry
195 OpMemoryModel Logical GLSL450
196 OpEntryPoint Geometry %main "main"
197 OpExecutionMode %main OutputPoints
198 )" + kVoidFunction;
199 
200   CompileSuccessfully(spirv);
201   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
202   EXPECT_THAT(
203       getDiagnosticString(),
204       HasSubstr("Geometry execution model entry points must specify exactly "
205                 "one of InputPoints, InputLines, InputLinesAdjacency, "
206                 "Triangles or InputTrianglesAdjacency execution modes."));
207 }
208 
TEST_F(ValidateMode,FragmentNoOrigin)209 TEST_F(ValidateMode, FragmentNoOrigin) {
210   const std::string spirv = R"(
211 OpCapability Shader
212 OpMemoryModel Logical GLSL450
213 OpEntryPoint Fragment %main "main"
214 )" + kVoidFunction;
215 
216   CompileSuccessfully(spirv);
217   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
218   EXPECT_THAT(
219       getDiagnosticString(),
220       HasSubstr("Fragment execution model entry points require either an "
221                 "OriginUpperLeft or OriginLowerLeft execution mode."));
222 }
223 
TEST_F(ValidateMode,FragmentBothOrigins)224 TEST_F(ValidateMode, FragmentBothOrigins) {
225   const std::string spirv = R"(
226 OpCapability Shader
227 OpMemoryModel Logical GLSL450
228 OpEntryPoint Fragment %main "main"
229 OpExecutionMode %main OriginUpperLeft
230 OpExecutionMode %main OriginLowerLeft
231 )" + kVoidFunction;
232 
233   CompileSuccessfully(spirv);
234   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
235   EXPECT_THAT(
236       getDiagnosticString(),
237       HasSubstr("Fragment execution model entry points can only specify one of "
238                 "OriginUpperLeft or OriginLowerLeft execution modes."));
239 }
240 
TEST_F(ValidateMode,FragmentDepthGreaterAndLess)241 TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
242   const std::string spirv = R"(
243 OpCapability Shader
244 OpMemoryModel Logical GLSL450
245 OpEntryPoint Fragment %main "main"
246 OpExecutionMode %main OriginUpperLeft
247 OpExecutionMode %main DepthGreater
248 OpExecutionMode %main DepthLess
249 )" + kVoidFunction;
250 
251   CompileSuccessfully(spirv);
252   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
253   EXPECT_THAT(getDiagnosticString(),
254               HasSubstr("Fragment execution model entry points can specify at "
255                         "most one of DepthGreater, DepthLess or DepthUnchanged "
256                         "execution modes."));
257 }
258 
TEST_F(ValidateMode,FragmentDepthGreaterAndUnchanged)259 TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
260   const std::string spirv = R"(
261 OpCapability Shader
262 OpMemoryModel Logical GLSL450
263 OpEntryPoint Fragment %main "main"
264 OpExecutionMode %main OriginUpperLeft
265 OpExecutionMode %main DepthGreater
266 OpExecutionMode %main DepthUnchanged
267 )" + kVoidFunction;
268 
269   CompileSuccessfully(spirv);
270   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
271   EXPECT_THAT(getDiagnosticString(),
272               HasSubstr("Fragment execution model entry points can specify at "
273                         "most one of DepthGreater, DepthLess or DepthUnchanged "
274                         "execution modes."));
275 }
276 
TEST_F(ValidateMode,FragmentDepthLessAndUnchanged)277 TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
278   const std::string spirv = R"(
279 OpCapability Shader
280 OpMemoryModel Logical GLSL450
281 OpEntryPoint Fragment %main "main"
282 OpExecutionMode %main OriginUpperLeft
283 OpExecutionMode %main DepthLess
284 OpExecutionMode %main DepthUnchanged
285 )" + kVoidFunction;
286 
287   CompileSuccessfully(spirv);
288   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
289   EXPECT_THAT(getDiagnosticString(),
290               HasSubstr("Fragment execution model entry points can specify at "
291                         "most one of DepthGreater, DepthLess or DepthUnchanged "
292                         "execution modes."));
293 }
294 
TEST_F(ValidateMode,FragmentAllDepths)295 TEST_F(ValidateMode, FragmentAllDepths) {
296   const std::string spirv = R"(
297 OpCapability Shader
298 OpMemoryModel Logical GLSL450
299 OpEntryPoint Fragment %main "main"
300 OpExecutionMode %main OriginUpperLeft
301 OpExecutionMode %main DepthGreater
302 OpExecutionMode %main DepthLess
303 OpExecutionMode %main DepthUnchanged
304 )" + kVoidFunction;
305 
306   CompileSuccessfully(spirv);
307   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
308   EXPECT_THAT(getDiagnosticString(),
309               HasSubstr("Fragment execution model entry points can specify at "
310                         "most one of DepthGreater, DepthLess or DepthUnchanged "
311                         "execution modes."));
312 }
313 
TEST_F(ValidateMode,TessellationControlSpacingEqualAndFractionalOdd)314 TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
315   const std::string spirv = R"(
316 OpCapability Tessellation
317 OpMemoryModel Logical GLSL450
318 OpEntryPoint TessellationControl %main "main"
319 OpExecutionMode %main SpacingEqual
320 OpExecutionMode %main SpacingFractionalOdd
321 )" + kVoidFunction;
322 
323   CompileSuccessfully(spirv);
324   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
325   EXPECT_THAT(getDiagnosticString(),
326               HasSubstr("Tessellation execution model entry points can specify "
327                         "at most one of SpacingEqual, SpacingFractionalOdd or "
328                         "SpacingFractionalEven execution modes."));
329 }
330 
TEST_F(ValidateMode,TessellationControlSpacingEqualAndSpacingFractionalEven)331 TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
332   const std::string spirv = R"(
333 OpCapability Tessellation
334 OpMemoryModel Logical GLSL450
335 OpEntryPoint TessellationControl %main "main"
336 OpExecutionMode %main SpacingEqual
337 OpExecutionMode %main SpacingFractionalEven
338 )" + kVoidFunction;
339 
340   CompileSuccessfully(spirv);
341   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
342   EXPECT_THAT(getDiagnosticString(),
343               HasSubstr("Tessellation execution model entry points can specify "
344                         "at most one of SpacingEqual, SpacingFractionalOdd or "
345                         "SpacingFractionalEven execution modes."));
346 }
347 
TEST_F(ValidateMode,TessellationControlSpacingFractionalOddAndSpacingFractionalEven)348 TEST_F(ValidateMode,
349        TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
350   const std::string spirv = R"(
351 OpCapability Tessellation
352 OpMemoryModel Logical GLSL450
353 OpEntryPoint TessellationControl %main "main"
354 OpExecutionMode %main SpacingFractionalOdd
355 OpExecutionMode %main SpacingFractionalEven
356 )" + kVoidFunction;
357 
358   CompileSuccessfully(spirv);
359   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
360   EXPECT_THAT(getDiagnosticString(),
361               HasSubstr("Tessellation execution model entry points can specify "
362                         "at most one of SpacingEqual, SpacingFractionalOdd or "
363                         "SpacingFractionalEven execution modes."));
364 }
365 
TEST_F(ValidateMode,TessellationControlAllSpacing)366 TEST_F(ValidateMode, TessellationControlAllSpacing) {
367   const std::string spirv = R"(
368 OpCapability Tessellation
369 OpMemoryModel Logical GLSL450
370 OpEntryPoint TessellationControl %main "main"
371 OpExecutionMode %main SpacingEqual
372 OpExecutionMode %main SpacingFractionalOdd
373 OpExecutionMode %main SpacingFractionalEven
374 )" + kVoidFunction;
375 
376   CompileSuccessfully(spirv);
377   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
378   EXPECT_THAT(getDiagnosticString(),
379               HasSubstr("Tessellation execution model entry points can specify "
380                         "at most one of SpacingEqual, SpacingFractionalOdd or "
381                         "SpacingFractionalEven execution modes."));
382 }
383 
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalOdd)384 TEST_F(ValidateMode,
385        TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
386   const std::string spirv = R"(
387 OpCapability Tessellation
388 OpMemoryModel Logical GLSL450
389 OpEntryPoint TessellationEvaluation %main "main"
390 OpExecutionMode %main SpacingEqual
391 OpExecutionMode %main SpacingFractionalOdd
392 )" + kVoidFunction;
393 
394   CompileSuccessfully(spirv);
395   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
396   EXPECT_THAT(getDiagnosticString(),
397               HasSubstr("Tessellation execution model entry points can specify "
398                         "at most one of SpacingEqual, SpacingFractionalOdd or "
399                         "SpacingFractionalEven execution modes."));
400 }
401 
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalEven)402 TEST_F(ValidateMode,
403        TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
404   const std::string spirv = R"(
405 OpCapability Tessellation
406 OpMemoryModel Logical GLSL450
407 OpEntryPoint TessellationEvaluation %main "main"
408 OpExecutionMode %main SpacingEqual
409 OpExecutionMode %main SpacingFractionalEven
410 )" + kVoidFunction;
411 
412   CompileSuccessfully(spirv);
413   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
414   EXPECT_THAT(getDiagnosticString(),
415               HasSubstr("Tessellation execution model entry points can specify "
416                         "at most one of SpacingEqual, SpacingFractionalOdd or "
417                         "SpacingFractionalEven execution modes."));
418 }
419 
TEST_F(ValidateMode,TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven)420 TEST_F(ValidateMode,
421        TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
422   const std::string spirv = R"(
423 OpCapability Tessellation
424 OpMemoryModel Logical GLSL450
425 OpEntryPoint TessellationEvaluation %main "main"
426 OpExecutionMode %main SpacingFractionalOdd
427 OpExecutionMode %main SpacingFractionalEven
428 )" + kVoidFunction;
429 
430   CompileSuccessfully(spirv);
431   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
432   EXPECT_THAT(getDiagnosticString(),
433               HasSubstr("Tessellation execution model entry points can specify "
434                         "at most one of SpacingEqual, SpacingFractionalOdd or "
435                         "SpacingFractionalEven execution modes."));
436 }
437 
TEST_F(ValidateMode,TessellationEvaluationAllSpacing)438 TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
439   const std::string spirv = R"(
440 OpCapability Tessellation
441 OpMemoryModel Logical GLSL450
442 OpEntryPoint TessellationEvaluation %main "main"
443 OpExecutionMode %main SpacingEqual
444 OpExecutionMode %main SpacingFractionalOdd
445 OpExecutionMode %main SpacingFractionalEven
446 )" + kVoidFunction;
447 
448   CompileSuccessfully(spirv);
449   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
450   EXPECT_THAT(getDiagnosticString(),
451               HasSubstr("Tessellation execution model entry points can specify "
452                         "at most one of SpacingEqual, SpacingFractionalOdd or "
453                         "SpacingFractionalEven execution modes."));
454 }
455 
TEST_F(ValidateMode,TessellationControlBothVertex)456 TEST_F(ValidateMode, TessellationControlBothVertex) {
457   const std::string spirv = R"(
458 OpCapability Tessellation
459 OpMemoryModel Logical GLSL450
460 OpEntryPoint TessellationControl %main "main"
461 OpExecutionMode %main VertexOrderCw
462 OpExecutionMode %main VertexOrderCcw
463 )" + kVoidFunction;
464 
465   CompileSuccessfully(spirv);
466   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
467   EXPECT_THAT(
468       getDiagnosticString(),
469       HasSubstr("Tessellation execution model entry points can specify at most "
470                 "one of VertexOrderCw or VertexOrderCcw execution modes."));
471 }
472 
TEST_F(ValidateMode,TessellationEvaluationBothVertex)473 TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
474   const std::string spirv = R"(
475 OpCapability Tessellation
476 OpMemoryModel Logical GLSL450
477 OpEntryPoint TessellationEvaluation %main "main"
478 OpExecutionMode %main VertexOrderCw
479 OpExecutionMode %main VertexOrderCcw
480 )" + kVoidFunction;
481 
482   CompileSuccessfully(spirv);
483   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
484   EXPECT_THAT(
485       getDiagnosticString(),
486       HasSubstr("Tessellation execution model entry points can specify at most "
487                 "one of VertexOrderCw or VertexOrderCcw execution modes."));
488 }
489 
490 using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
491     std::tuple<std::string, std::string, std::string, std::string, std::string>,
492     std::tuple<std::string, std::string, std::string>>>;
493 
TEST_P(ValidateModeGeometry,ExecutionMode)494 TEST_P(ValidateModeGeometry, ExecutionMode) {
495   std::vector<std::string> input_modes;
496   std::vector<std::string> output_modes;
497   input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
498   input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
499   input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
500   input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
501   input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
502   output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
503   output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
504   output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
505 
506   std::ostringstream sstr;
507   sstr << "OpCapability Geometry\n";
508   sstr << "OpMemoryModel Logical GLSL450\n";
509   sstr << "OpEntryPoint Geometry %main \"main\"\n";
510   size_t num_input_modes = 0;
511   for (auto input : input_modes) {
512     if (!input.empty()) {
513       num_input_modes++;
514       sstr << "OpExecutionMode %main " << input << "\n";
515     }
516   }
517   size_t num_output_modes = 0;
518   for (auto output : output_modes) {
519     if (!output.empty()) {
520       num_output_modes++;
521       sstr << "OpExecutionMode %main " << output << "\n";
522     }
523   }
524   sstr << "%void = OpTypeVoid\n";
525   sstr << "%void_fn = OpTypeFunction %void\n";
526   sstr << "%int = OpTypeInt 32 0\n";
527   sstr << "%int1 = OpConstant %int 1\n";
528   sstr << "%main = OpFunction %void None %void_fn\n";
529   sstr << "%entry = OpLabel\n";
530   sstr << "OpReturn\n";
531   sstr << "OpFunctionEnd\n";
532 
533   CompileSuccessfully(sstr.str());
534   if (num_input_modes == 1 && num_output_modes == 1) {
535     EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
536   } else {
537     EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
538     if (num_input_modes != 1) {
539       EXPECT_THAT(getDiagnosticString(),
540                   HasSubstr("Geometry execution model entry points must "
541                             "specify exactly one of InputPoints, InputLines, "
542                             "InputLinesAdjacency, Triangles or "
543                             "InputTrianglesAdjacency execution modes."));
544     } else {
545       EXPECT_THAT(
546           getDiagnosticString(),
547           HasSubstr("Geometry execution model entry points must specify "
548                     "exactly one of OutputPoints, OutputLineStrip or "
549                     "OutputTriangleStrip execution modes."));
550     }
551   }
552 }
553 
554 INSTANTIATE_TEST_SUITE_P(
555     GeometryRequiredModes, ValidateModeGeometry,
556     Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
557                     Values("InputLinesAdjacency", ""), Values("Triangles", ""),
558                     Values("InputTrianglesAdjacency", "")),
559             Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
560                     Values("OutputTriangleStrip", ""))));
561 
562 using ValidateModeExecution =
563     spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
564                                      std::string, spv_target_env>>;
565 
TEST_P(ValidateModeExecution,ExecutionMode)566 TEST_P(ValidateModeExecution, ExecutionMode) {
567   const spv_result_t expectation = std::get<0>(GetParam());
568   const std::string error = std::get<1>(GetParam());
569   const std::string model = std::get<2>(GetParam());
570   const std::string mode = std::get<3>(GetParam());
571   const spv_target_env env = std::get<4>(GetParam());
572 
573   std::ostringstream sstr;
574   sstr << "OpCapability Shader\n";
575   sstr << "OpCapability Geometry\n";
576   sstr << "OpCapability Tessellation\n";
577   sstr << "OpCapability TransformFeedback\n";
578   if (!spvIsVulkanEnv(env)) {
579     sstr << "OpCapability Kernel\n";
580     if (env == SPV_ENV_UNIVERSAL_1_3) {
581       sstr << "OpCapability SubgroupDispatch\n";
582     }
583   }
584   sstr << "OpMemoryModel Logical GLSL450\n";
585   sstr << "OpEntryPoint " << model << " %main \"main\"\n";
586   if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
587       mode.find("SubgroupsPerWorkgroupId") == 0) {
588     sstr << "OpExecutionModeId %main " << mode << "\n";
589   } else {
590     sstr << "OpExecutionMode %main " << mode << "\n";
591   }
592   if (model == "Geometry") {
593     if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
594           mode.find("InputLinesAdjacency") == 0 ||
595           mode.find("Triangles") == 0 ||
596           mode.find("InputTrianglesAdjacency") == 0)) {
597       // Exactly one of the above modes is required for Geometry shaders.
598       sstr << "OpExecutionMode %main InputPoints\n";
599     }
600     if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
601           mode.find("OutputTriangleStrip") == 0)) {
602       // Exactly one of the above modes is required for Geometry shaders.
603       sstr << "OpExecutionMode %main OutputPoints\n";
604     }
605   } else if (model == "Fragment") {
606     if (!(mode.find("OriginUpperLeft") == 0 ||
607           mode.find("OriginLowerLeft") == 0)) {
608       // Exactly one of the above modes is required for Fragment shaders.
609       sstr << "OpExecutionMode %main OriginUpperLeft\n";
610     }
611   }
612   sstr << "%void = OpTypeVoid\n";
613   sstr << "%void_fn = OpTypeFunction %void\n";
614   sstr << "%int = OpTypeInt 32 0\n";
615   sstr << "%int1 = OpConstant %int 1\n";
616   sstr << "%main = OpFunction %void None %void_fn\n";
617   sstr << "%entry = OpLabel\n";
618   sstr << "OpReturn\n";
619   sstr << "OpFunctionEnd\n";
620 
621   CompileSuccessfully(sstr.str(), env);
622   EXPECT_THAT(expectation, ValidateInstructions(env));
623   if (expectation != SPV_SUCCESS) {
624     EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
625   }
626 }
627 
628 INSTANTIATE_TEST_SUITE_P(
629     ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
630     Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
631             Values("Invocations 3", "InputPoints", "InputLines",
632                    "InputLinesAdjacency", "InputTrianglesAdjacency",
633                    "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
634             Values(SPV_ENV_UNIVERSAL_1_0)));
635 
636 INSTANTIATE_TEST_SUITE_P(
637     ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
638     Combine(Values(SPV_ERROR_INVALID_DATA),
639             Values("Execution mode can only be used with the Geometry "
640                    "execution model."),
641             Values("Fragment", "TessellationEvaluation", "TessellationControl",
642                    "GLCompute", "Vertex", "Kernel"),
643             Values("Invocations 3", "InputPoints", "InputLines",
644                    "InputLinesAdjacency", "InputTrianglesAdjacency",
645                    "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
646             Values(SPV_ENV_UNIVERSAL_1_0)));
647 
648 INSTANTIATE_TEST_SUITE_P(
649     ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
650     Combine(Values(SPV_SUCCESS), Values(""),
651             Values("TessellationControl", "TessellationEvaluation"),
652             Values("SpacingEqual", "SpacingFractionalEven",
653                    "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
654                    "PointMode", "Quads", "Isolines"),
655             Values(SPV_ENV_UNIVERSAL_1_0)));
656 
657 INSTANTIATE_TEST_SUITE_P(
658     ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
659     Combine(Values(SPV_ERROR_INVALID_DATA),
660             Values("Execution mode can only be used with a tessellation "
661                    "execution model."),
662             Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
663             Values("SpacingEqual", "SpacingFractionalEven",
664                    "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
665                    "PointMode", "Quads", "Isolines"),
666             Values(SPV_ENV_UNIVERSAL_1_0)));
667 
668 INSTANTIATE_TEST_SUITE_P(ValidateModeGeometryAndTessellationGoodSpv10,
669                          ValidateModeExecution,
670                          Combine(Values(SPV_SUCCESS), Values(""),
671                                  Values("TessellationControl",
672                                         "TessellationEvaluation", "Geometry"),
673                                  Values("Triangles", "OutputVertices 3"),
674                                  Values(SPV_ENV_UNIVERSAL_1_0)));
675 
676 INSTANTIATE_TEST_SUITE_P(
677     ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
678     Combine(Values(SPV_ERROR_INVALID_DATA),
679             Values("Execution mode can only be used with a Geometry or "
680                    "tessellation execution model."),
681             Values("Fragment", "GLCompute", "Vertex", "Kernel"),
682             Values("Triangles", "OutputVertices 3"),
683             Values(SPV_ENV_UNIVERSAL_1_0)));
684 
685 INSTANTIATE_TEST_SUITE_P(
686     ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
687     Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
688             Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
689                    "EarlyFragmentTests", "DepthReplacing", "DepthLess",
690                    "DepthUnchanged"),
691             Values(SPV_ENV_UNIVERSAL_1_0)));
692 
693 INSTANTIATE_TEST_SUITE_P(
694     ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
695     Combine(Values(SPV_ERROR_INVALID_DATA),
696             Values("Execution mode can only be used with the Fragment "
697                    "execution model."),
698             Values("Geometry", "TessellationControl", "TessellationEvaluation",
699                    "GLCompute", "Vertex", "Kernel"),
700             Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
701                    "EarlyFragmentTests", "DepthReplacing", "DepthGreater",
702                    "DepthLess", "DepthUnchanged"),
703             Values(SPV_ENV_UNIVERSAL_1_0)));
704 
705 INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
706                          Combine(Values(SPV_SUCCESS), Values(""),
707                                  Values("Kernel"),
708                                  Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
709                                         "ContractionOff",
710                                         "LocalSizeHintId %int1 %int1 %int1"),
711                                  Values(SPV_ENV_UNIVERSAL_1_3)));
712 
713 INSTANTIATE_TEST_SUITE_P(
714     ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
715     Combine(
716         Values(SPV_ERROR_INVALID_DATA),
717         Values(
718             "Execution mode can only be used with the Kernel execution model."),
719         Values("Geometry", "TessellationControl", "TessellationEvaluation",
720                "GLCompute", "Vertex", "Fragment"),
721         Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
722                "LocalSizeHintId %int1 %int1 %int1"),
723         Values(SPV_ENV_UNIVERSAL_1_3)));
724 
725 INSTANTIATE_TEST_SUITE_P(
726     ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
727     Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
728             Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
729             Values(SPV_ENV_UNIVERSAL_1_3)));
730 
731 INSTANTIATE_TEST_SUITE_P(
732     ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
733     Combine(Values(SPV_ERROR_INVALID_DATA),
734             Values("Execution mode can only be used with a Kernel or GLCompute "
735                    "execution model."),
736             Values("Geometry", "TessellationControl", "TessellationEvaluation",
737                    "Fragment", "Vertex"),
738             Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
739             Values(SPV_ENV_UNIVERSAL_1_3)));
740 
741 INSTANTIATE_TEST_SUITE_P(
742     ValidateModeAllGoodSpv13, ValidateModeExecution,
743     Combine(Values(SPV_SUCCESS), Values(""),
744             Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
745                    "TessellationEvaluation", "Fragment", "Vertex"),
746             Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
747                    "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
748             Values(SPV_ENV_UNIVERSAL_1_3)));
749 
TEST_F(ValidateModeExecution,MeshNVLocalSize)750 TEST_F(ValidateModeExecution, MeshNVLocalSize) {
751   const std::string spirv = R"(
752 OpCapability Shader
753 OpCapability MeshShadingNV
754 OpExtension "SPV_NV_mesh_shader"
755 OpMemoryModel Logical GLSL450
756 OpEntryPoint MeshNV %main "main"
757 OpExecutionMode %main LocalSize 1 1 1
758 )" + kVoidFunction;
759 
760   CompileSuccessfully(spirv);
761   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
762 }
763 
TEST_F(ValidateModeExecution,TaskNVLocalSize)764 TEST_F(ValidateModeExecution, TaskNVLocalSize) {
765   const std::string spirv = R"(
766 OpCapability Shader
767 OpCapability MeshShadingNV
768 OpExtension "SPV_NV_mesh_shader"
769 OpMemoryModel Logical GLSL450
770 OpEntryPoint TaskNV %main "main"
771 OpExecutionMode %main LocalSize 1 1 1
772 )" + kVoidFunction;
773 
774   CompileSuccessfully(spirv);
775   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
776 }
777 
TEST_F(ValidateModeExecution,MeshNVOutputPoints)778 TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
779   const std::string spirv = R"(
780 OpCapability Shader
781 OpCapability MeshShadingNV
782 OpExtension "SPV_NV_mesh_shader"
783 OpMemoryModel Logical GLSL450
784 OpEntryPoint MeshNV %main "main"
785 OpExecutionMode %main OutputPoints
786 )" + kVoidFunction;
787 
788   CompileSuccessfully(spirv);
789   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
790 }
791 
TEST_F(ValidateModeExecution,MeshNVOutputVertices)792 TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
793   const std::string spirv = R"(
794 OpCapability Shader
795 OpCapability MeshShadingNV
796 OpExtension "SPV_NV_mesh_shader"
797 OpMemoryModel Logical GLSL450
798 OpEntryPoint MeshNV %main "main"
799 OpExecutionMode %main OutputVertices 42
800 )" + kVoidFunction;
801 
802   CompileSuccessfully(spirv);
803   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
804 }
805 
TEST_F(ValidateModeExecution,MeshNVLocalSizeId)806 TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
807   const std::string spirv = R"(
808 OpCapability Shader
809 OpCapability MeshShadingNV
810 OpExtension "SPV_NV_mesh_shader"
811 OpMemoryModel Logical GLSL450
812 OpEntryPoint MeshNV %main "main"
813 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
814 %int = OpTypeInt 32 0
815 %int_1 = OpConstant %int 1
816 )" + kVoidFunction;
817 
818   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
819   CompileSuccessfully(spirv, env);
820   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
821 }
822 
TEST_F(ValidateModeExecution,TaskNVLocalSizeId)823 TEST_F(ValidateModeExecution, TaskNVLocalSizeId) {
824   const std::string spirv = R"(
825 OpCapability Shader
826 OpCapability MeshShadingNV
827 OpExtension "SPV_NV_mesh_shader"
828 OpMemoryModel Logical GLSL450
829 OpEntryPoint TaskNV %main "main"
830 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
831 %int = OpTypeInt 32 0
832 %int_1 = OpConstant %int 1
833 )" + kVoidFunction;
834 
835   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
836   CompileSuccessfully(spirv, env);
837   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
838 }
839 
TEST_F(ValidateModeExecution,ExecModeSubgroupsPerWorkgroupIdBad)840 TEST_F(ValidateModeExecution, ExecModeSubgroupsPerWorkgroupIdBad) {
841   const std::string spirv = R"(
842 OpCapability Shader
843 OpCapability SubgroupDispatch
844 OpMemoryModel Logical GLSL450
845 OpEntryPoint Vertex %main "main"
846 OpExecutionMode %main SubgroupsPerWorkgroupId %int_1
847 %int = OpTypeInt 32 0
848 %int_1 = OpConstant %int 1
849 )" + kVoidFunction;
850 
851   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
852   CompileSuccessfully(spirv, env);
853   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
854   EXPECT_THAT(getDiagnosticString(),
855               HasSubstr("OpExecutionMode is only valid when the Mode operand "
856                         "is an execution mode that takes no Extra Operands"));
857 }
858 
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdGood)859 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdGood) {
860   const std::string spirv = R"(
861 OpCapability Shader
862 OpCapability SubgroupDispatch
863 OpMemoryModel Logical GLSL450
864 OpEntryPoint Vertex %main "main"
865 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
866 %int = OpTypeInt 32 0
867 %int_1 = OpConstant %int 1
868 )" + kVoidFunction;
869 
870   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
871   CompileSuccessfully(spirv, env);
872   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
873 }
874 
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad)875 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad) {
876   const std::string spirv = R"(
877 OpCapability Shader
878 OpCapability SubgroupDispatch
879 OpMemoryModel Logical GLSL450
880 OpEntryPoint Vertex %main "main"
881 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
882 %int = OpTypeInt 32 0
883 %int_ptr = OpTypePointer Private %int
884 %int_1 = OpVariable %int_ptr Private
885 )" + kVoidFunction;
886 
887   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
888   CompileSuccessfully(spirv, env);
889   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
890   EXPECT_THAT(getDiagnosticString(),
891               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
892                         "constant instructions."));
893 }
894 
TEST_F(ValidateModeExecution,ExecModeLocalSizeHintIdBad)895 TEST_F(ValidateModeExecution, ExecModeLocalSizeHintIdBad) {
896   const std::string spirv = R"(
897 OpCapability Kernel
898 OpCapability Shader
899 OpMemoryModel Logical GLSL450
900 OpEntryPoint Kernel %main "main"
901 OpExecutionMode %main LocalSizeHintId %int_1 %int_1 %int_1
902 %int = OpTypeInt 32 0
903 %int_1 = OpConstant %int 1
904 )" + kVoidFunction;
905 
906   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
907   CompileSuccessfully(spirv, env);
908   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
909   EXPECT_THAT(getDiagnosticString(),
910               HasSubstr("OpExecutionMode is only valid when the Mode operand "
911                         "is an execution mode that takes no Extra Operands"));
912 }
913 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdGood)914 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdGood) {
915   const std::string spirv = R"(
916 OpCapability Kernel
917 OpCapability Shader
918 OpMemoryModel Logical GLSL450
919 OpEntryPoint Kernel %main "main"
920 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
921 %int = OpTypeInt 32 0
922 %int_1 = OpConstant %int 1
923 )" + kVoidFunction;
924 
925   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
926   CompileSuccessfully(spirv, env);
927   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
928 }
929 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdNonConstantBad)930 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdNonConstantBad) {
931   const std::string spirv = R"(
932 OpCapability Kernel
933 OpCapability Shader
934 OpMemoryModel Logical GLSL450
935 OpEntryPoint Vertex %main "main"
936 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
937 %int = OpTypeInt 32 0
938 %int_ptr = OpTypePointer Private %int
939 %int_1 = OpVariable %int_ptr Private
940 )" + kVoidFunction;
941 
942   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
943   CompileSuccessfully(spirv, env);
944   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
945   EXPECT_THAT(getDiagnosticString(),
946               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
947                         "constant instructions."));
948 }
949 
TEST_F(ValidateModeExecution,ExecModeLocalSizeIdBad)950 TEST_F(ValidateModeExecution, ExecModeLocalSizeIdBad) {
951   const std::string spirv = R"(
952 OpCapability Kernel
953 OpCapability Shader
954 OpMemoryModel Logical GLSL450
955 OpEntryPoint Kernel %main "main"
956 OpExecutionMode %main LocalSizeId %int_1 %int_1 %int_1
957 %int = OpTypeInt 32 0
958 %int_1 = OpConstant %int 1
959 )" + kVoidFunction;
960 
961   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
962   CompileSuccessfully(spirv, env);
963   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
964   EXPECT_THAT(getDiagnosticString(),
965               HasSubstr("OpExecutionMode is only valid when the Mode operand "
966                         "is an execution mode that takes no Extra Operands"));
967 }
968 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdGood)969 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdGood) {
970   const std::string spirv = R"(
971 OpCapability Kernel
972 OpCapability Shader
973 OpMemoryModel Logical GLSL450
974 OpEntryPoint Kernel %main "main"
975 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
976 %int = OpTypeInt 32 0
977 %int_1 = OpConstant %int 1
978 )" + kVoidFunction;
979 
980   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
981   CompileSuccessfully(spirv, env);
982   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
983 }
984 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdNonConstantBad)985 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdNonConstantBad) {
986   const std::string spirv = R"(
987 OpCapability Kernel
988 OpCapability Shader
989 OpMemoryModel Logical GLSL450
990 OpEntryPoint Vertex %main "main"
991 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
992 %int = OpTypeInt 32 0
993 %int_ptr = OpTypePointer Private %int
994 %int_1 = OpVariable %int_ptr Private
995 )" + kVoidFunction;
996 
997   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
998   CompileSuccessfully(spirv, env);
999   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
1000   EXPECT_THAT(getDiagnosticString(),
1001               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
1002                         "constant instructions."));
1003 }
1004 
TEST_F(ValidateMode,FragmentShaderInterlockVertexBad)1005 TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) {
1006   const std::string spirv = R"(
1007 OpCapability Shader
1008 OpCapability FragmentShaderPixelInterlockEXT
1009 OpExtension "SPV_EXT_fragment_shader_interlock"
1010 OpMemoryModel Logical GLSL450
1011 OpEntryPoint Vertex %main "main"
1012 OpExecutionMode %main PixelInterlockOrderedEXT
1013 )" + kVoidFunction;
1014 
1015   CompileSuccessfully(spirv);
1016   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1017   EXPECT_THAT(
1018       getDiagnosticString(),
1019       HasSubstr(
1020           "Execution mode can only be used with the Fragment execution model"));
1021 }
1022 
TEST_F(ValidateMode,FragmentShaderInterlockTooManyModesBad)1023 TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) {
1024   const std::string spirv = R"(
1025 OpCapability Shader
1026 OpCapability FragmentShaderPixelInterlockEXT
1027 OpCapability FragmentShaderSampleInterlockEXT
1028 OpExtension "SPV_EXT_fragment_shader_interlock"
1029 OpMemoryModel Logical GLSL450
1030 OpEntryPoint Fragment %main "main"
1031 OpExecutionMode %main OriginUpperLeft
1032 OpExecutionMode %main PixelInterlockOrderedEXT
1033 OpExecutionMode %main SampleInterlockOrderedEXT
1034 )" + kVoidFunction;
1035 
1036   CompileSuccessfully(spirv);
1037   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1038   EXPECT_THAT(
1039       getDiagnosticString(),
1040       HasSubstr("Fragment execution model entry points can specify at most "
1041                 "one fragment shader interlock execution mode"));
1042 }
1043 
TEST_F(ValidateMode,FragmentShaderInterlockNoModeBad)1044 TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) {
1045   const std::string spirv = R"(
1046 OpCapability Shader
1047 OpCapability FragmentShaderPixelInterlockEXT
1048 OpExtension "SPV_EXT_fragment_shader_interlock"
1049 OpMemoryModel Logical GLSL450
1050 OpEntryPoint Fragment %main "main"
1051 OpExecutionMode %main OriginUpperLeft
1052 %void = OpTypeVoid
1053 %void_fn = OpTypeFunction %void
1054 %func = OpFunction %void None %void_fn
1055 %entryf = OpLabel
1056 OpBeginInvocationInterlockEXT
1057 OpEndInvocationInterlockEXT
1058 OpReturn
1059 OpFunctionEnd
1060 %main = OpFunction %void None %void_fn
1061 %entry = OpLabel
1062 %1 = OpFunctionCall %void %func
1063 OpReturn
1064 OpFunctionEnd
1065 )";
1066 
1067   CompileSuccessfully(spirv);
1068   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1069   EXPECT_THAT(
1070       getDiagnosticString(),
1071       HasSubstr(
1072           "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a "
1073           "fragment shader interlock execution mode"));
1074 }
1075 
TEST_F(ValidateMode,FragmentShaderInterlockGood)1076 TEST_F(ValidateMode, FragmentShaderInterlockGood) {
1077   const std::string spirv = R"(
1078 OpCapability Shader
1079 OpCapability FragmentShaderPixelInterlockEXT
1080 OpExtension "SPV_EXT_fragment_shader_interlock"
1081 OpMemoryModel Logical GLSL450
1082 OpEntryPoint Fragment %main "main"
1083 OpExecutionMode %main OriginUpperLeft
1084 OpExecutionMode %main PixelInterlockOrderedEXT
1085 %void = OpTypeVoid
1086 %void_fn = OpTypeFunction %void
1087 %func = OpFunction %void None %void_fn
1088 %entryf = OpLabel
1089 OpBeginInvocationInterlockEXT
1090 OpEndInvocationInterlockEXT
1091 OpReturn
1092 OpFunctionEnd
1093 %main = OpFunction %void None %void_fn
1094 %entry = OpLabel
1095 %1 = OpFunctionCall %void %func
1096 OpReturn
1097 OpFunctionEnd
1098 )";
1099 
1100   CompileSuccessfully(spirv);
1101   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1102 }
1103 
TEST_F(ValidateMode,FragmentShaderDemoteVertexBad)1104 TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) {
1105   const std::string spirv = R"(
1106 OpCapability Shader
1107 OpCapability DemoteToHelperInvocationEXT
1108 OpExtension "SPV_EXT_demote_to_helper_invocation"
1109 OpMemoryModel Logical GLSL450
1110 OpEntryPoint Vertex %main "main"
1111 %bool = OpTypeBool
1112 %void = OpTypeVoid
1113 %void_fn = OpTypeFunction %void
1114 %main = OpFunction %void None %void_fn
1115 %entry = OpLabel
1116 OpDemoteToHelperInvocationEXT
1117 %1 = OpIsHelperInvocationEXT %bool
1118 OpReturn
1119 OpFunctionEnd
1120 )";
1121 
1122   CompileSuccessfully(spirv);
1123   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1124   EXPECT_THAT(
1125       getDiagnosticString(),
1126       HasSubstr(
1127           "OpDemoteToHelperInvocationEXT requires Fragment execution model"));
1128   EXPECT_THAT(
1129       getDiagnosticString(),
1130       HasSubstr("OpIsHelperInvocationEXT requires Fragment execution model"));
1131 }
1132 
TEST_F(ValidateMode,FragmentShaderDemoteGood)1133 TEST_F(ValidateMode, FragmentShaderDemoteGood) {
1134   const std::string spirv = R"(
1135 OpCapability Shader
1136 OpCapability DemoteToHelperInvocationEXT
1137 OpExtension "SPV_EXT_demote_to_helper_invocation"
1138 OpMemoryModel Logical GLSL450
1139 OpEntryPoint Fragment %main "main"
1140 OpExecutionMode %main OriginUpperLeft
1141 %bool = OpTypeBool
1142 %void = OpTypeVoid
1143 %void_fn = OpTypeFunction %void
1144 %main = OpFunction %void None %void_fn
1145 %entry = OpLabel
1146 OpDemoteToHelperInvocationEXT
1147 %1 = OpIsHelperInvocationEXT %bool
1148 OpReturn
1149 OpFunctionEnd
1150 )";
1151 
1152   CompileSuccessfully(spirv);
1153   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1154 }
1155 
TEST_F(ValidateMode,FragmentShaderDemoteBadType)1156 TEST_F(ValidateMode, FragmentShaderDemoteBadType) {
1157   const std::string spirv = R"(
1158 OpCapability Shader
1159 OpCapability DemoteToHelperInvocationEXT
1160 OpExtension "SPV_EXT_demote_to_helper_invocation"
1161 OpMemoryModel Logical GLSL450
1162 OpEntryPoint Fragment %main "main"
1163 OpExecutionMode %main OriginUpperLeft
1164 %u32 = OpTypeInt 32 0
1165 %void = OpTypeVoid
1166 %void_fn = OpTypeFunction %void
1167 %main = OpFunction %void None %void_fn
1168 %entry = OpLabel
1169 OpDemoteToHelperInvocationEXT
1170 %1 = OpIsHelperInvocationEXT %u32
1171 OpReturn
1172 OpFunctionEnd
1173 )";
1174 
1175   CompileSuccessfully(spirv);
1176   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1177   EXPECT_THAT(getDiagnosticString(),
1178               HasSubstr("Expected bool scalar type as Result Type"));
1179 }
1180 
TEST_F(ValidateMode,LocalSizeIdVulkan1p3DoesNotRequireOption)1181 TEST_F(ValidateMode, LocalSizeIdVulkan1p3DoesNotRequireOption) {
1182   const std::string spirv = R"(
1183 OpCapability Shader
1184 OpMemoryModel Logical GLSL450
1185 OpEntryPoint GLCompute %main "main"
1186 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
1187 %void = OpTypeVoid
1188 %int = OpTypeInt 32 0
1189 %int_1 = OpConstant %int 1
1190 %void_fn = OpTypeFunction %void
1191 %main = OpFunction %void None %void_fn
1192 %entry = OpLabel
1193 OpReturn
1194 OpFunctionEnd
1195 )";
1196 
1197   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
1198   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
1199 }
1200 
1201 }  // namespace
1202 }  // namespace val
1203 }  // namespace spvtools
1204