• 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/unit_spirv.h"
22 #include "test/val/val_fixtures.h"
23 
24 namespace spvtools {
25 namespace val {
26 namespace {
27 
28 using ::testing::Combine;
29 using ::testing::HasSubstr;
30 using ::testing::Values;
31 using ::testing::ValuesIn;
32 
33 using ValidateMode = spvtest::ValidateBase<bool>;
34 
35 const std::string kVoidFunction = R"(%void = OpTypeVoid
36 %void_fn = OpTypeFunction %void
37 %main = OpFunction %void None %void_fn
38 %entry = OpLabel
39 OpReturn
40 OpFunctionEnd
41 )";
42 
TEST_F(ValidateMode,GLComputeNoMode)43 TEST_F(ValidateMode, GLComputeNoMode) {
44   const std::string spirv = R"(
45 OpCapability Shader
46 OpMemoryModel Logical GLSL450
47 OpEntryPoint GLCompute %main "main"
48 )" + kVoidFunction;
49 
50   CompileSuccessfully(spirv);
51   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
52 }
53 
TEST_F(ValidateMode,GLComputeNoModeVulkan)54 TEST_F(ValidateMode, GLComputeNoModeVulkan) {
55   const std::string spirv = R"(
56 OpCapability Shader
57 OpMemoryModel Logical GLSL450
58 OpEntryPoint GLCompute %main "main"
59 )" + kVoidFunction;
60 
61   spv_target_env env = SPV_ENV_VULKAN_1_0;
62   CompileSuccessfully(spirv, env);
63   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
64   EXPECT_THAT(getDiagnosticString(),
65               AnyVUID("VUID-StandaloneSpirv-LocalSize-06426"));
66   EXPECT_THAT(
67       getDiagnosticString(),
68       HasSubstr(
69           "In the Vulkan environment, GLCompute execution model entry "
70           "points require either the LocalSize or LocalSizeId execution mode "
71           "or an object decorated with WorkgroupSize must be specified."));
72 }
73 
TEST_F(ValidateMode,GLComputeNoModeVulkanWorkgroupSize)74 TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
75   const std::string spirv = R"(
76 OpCapability Shader
77 OpMemoryModel Logical GLSL450
78 OpEntryPoint GLCompute %main "main"
79 OpDecorate %int3_1 BuiltIn WorkgroupSize
80 %int = OpTypeInt 32 0
81 %int3 = OpTypeVector %int 3
82 %int_1 = OpConstant %int 1
83 %int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
84 )" + kVoidFunction;
85 
86   spv_target_env env = SPV_ENV_VULKAN_1_0;
87   CompileSuccessfully(spirv, env);
88   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
89 }
90 
TEST_F(ValidateMode,GLComputeVulkanLocalSize)91 TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
92   const std::string spirv = R"(
93 OpCapability Shader
94 OpMemoryModel Logical GLSL450
95 OpEntryPoint GLCompute %main "main"
96 OpExecutionMode %main LocalSize 1 1 1
97 )" + kVoidFunction;
98 
99   spv_target_env env = SPV_ENV_VULKAN_1_0;
100   CompileSuccessfully(spirv, env);
101   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
102 }
103 
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdBad)104 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdBad) {
105   const std::string spirv = R"(
106 OpCapability Shader
107 OpMemoryModel Logical GLSL450
108 OpEntryPoint GLCompute %main "main"
109 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
110 %int = OpTypeInt 32 0
111 %int_1 = OpConstant %int 1
112 )" + kVoidFunction;
113 
114   spv_target_env env = SPV_ENV_VULKAN_1_1;  // need SPIR-V 1.2
115   CompileSuccessfully(spirv, env);
116   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
117   EXPECT_THAT(
118       getDiagnosticString(),
119       HasSubstr("LocalSizeId mode is not allowed by the current environment."));
120 }
121 
TEST_F(ValidateMode,GLComputeVulkanLocalSizeIdGood)122 TEST_F(ValidateMode, GLComputeVulkanLocalSizeIdGood) {
123   const std::string spirv = R"(
124 OpCapability Shader
125 OpMemoryModel Logical GLSL450
126 OpEntryPoint GLCompute %main "main"
127 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
128 %int = OpTypeInt 32 0
129 %int_1 = OpConstant %int 1
130 )" + kVoidFunction;
131 
132   spv_target_env env = SPV_ENV_VULKAN_1_1;  // need SPIR-V 1.2
133   CompileSuccessfully(spirv, env);
134   spvValidatorOptionsSetAllowLocalSizeId(getValidatorOptions(), true);
135   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
136 }
137 
TEST_F(ValidateMode,FragmentOriginLowerLeftVulkan)138 TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
139   const std::string spirv = R"(
140 OpCapability Shader
141 OpMemoryModel Logical GLSL450
142 OpEntryPoint Fragment %main "main"
143 OpExecutionMode %main OriginLowerLeft
144 )" + kVoidFunction;
145 
146   spv_target_env env = SPV_ENV_VULKAN_1_0;
147   CompileSuccessfully(spirv, env);
148   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
149   EXPECT_THAT(getDiagnosticString(),
150               AnyVUID("VUID-StandaloneSpirv-OriginLowerLeft-04653"));
151   EXPECT_THAT(getDiagnosticString(),
152               HasSubstr("In the Vulkan environment, the OriginLowerLeft "
153                         "execution mode must not be used."));
154 }
155 
TEST_F(ValidateMode,FragmentPixelCenterIntegerVulkan)156 TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
157   const std::string spirv = R"(
158 OpCapability Shader
159 OpMemoryModel Logical GLSL450
160 OpEntryPoint Fragment %main "main"
161 OpExecutionMode %main OriginUpperLeft
162 OpExecutionMode %main PixelCenterInteger
163 )" + kVoidFunction;
164 
165   spv_target_env env = SPV_ENV_VULKAN_1_0;
166   CompileSuccessfully(spirv, env);
167   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
168   EXPECT_THAT(getDiagnosticString(),
169               AnyVUID("VUID-StandaloneSpirv-PixelCenterInteger-04654"));
170   EXPECT_THAT(getDiagnosticString(),
171               HasSubstr("In the Vulkan environment, the PixelCenterInteger "
172                         "execution mode must not be used."));
173 }
174 
TEST_F(ValidateMode,GeometryNoOutputMode)175 TEST_F(ValidateMode, GeometryNoOutputMode) {
176   const std::string spirv = R"(
177 OpCapability Geometry
178 OpMemoryModel Logical GLSL450
179 OpEntryPoint Geometry %main "main"
180 OpExecutionMode %main InputPoints
181 )" + kVoidFunction;
182 
183   CompileSuccessfully(spirv);
184   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
185   EXPECT_THAT(getDiagnosticString(),
186               HasSubstr("Geometry execution model entry points must specify "
187                         "exactly one of OutputPoints, OutputLineStrip or "
188                         "OutputTriangleStrip execution modes."));
189 }
190 
TEST_F(ValidateMode,GeometryNoInputMode)191 TEST_F(ValidateMode, GeometryNoInputMode) {
192   const std::string spirv = R"(
193 OpCapability Geometry
194 OpMemoryModel Logical GLSL450
195 OpEntryPoint Geometry %main "main"
196 OpExecutionMode %main OutputPoints
197 )" + kVoidFunction;
198 
199   CompileSuccessfully(spirv);
200   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
201   EXPECT_THAT(
202       getDiagnosticString(),
203       HasSubstr("Geometry execution model entry points must specify exactly "
204                 "one of InputPoints, InputLines, InputLinesAdjacency, "
205                 "Triangles or InputTrianglesAdjacency execution modes."));
206 }
207 
TEST_F(ValidateMode,FragmentNoOrigin)208 TEST_F(ValidateMode, FragmentNoOrigin) {
209   const std::string spirv = R"(
210 OpCapability Shader
211 OpMemoryModel Logical GLSL450
212 OpEntryPoint Fragment %main "main"
213 )" + kVoidFunction;
214 
215   CompileSuccessfully(spirv);
216   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
217   EXPECT_THAT(
218       getDiagnosticString(),
219       HasSubstr("Fragment execution model entry points require either an "
220                 "OriginUpperLeft or OriginLowerLeft execution mode."));
221 }
222 
TEST_F(ValidateMode,FragmentBothOrigins)223 TEST_F(ValidateMode, FragmentBothOrigins) {
224   const std::string spirv = R"(
225 OpCapability Shader
226 OpMemoryModel Logical GLSL450
227 OpEntryPoint Fragment %main "main"
228 OpExecutionMode %main OriginUpperLeft
229 OpExecutionMode %main OriginLowerLeft
230 )" + kVoidFunction;
231 
232   CompileSuccessfully(spirv);
233   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
234   EXPECT_THAT(
235       getDiagnosticString(),
236       HasSubstr("Fragment execution model entry points can only specify one of "
237                 "OriginUpperLeft or OriginLowerLeft execution modes."));
238 }
239 
TEST_F(ValidateMode,FragmentDepthGreaterAndLess)240 TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
241   const std::string spirv = R"(
242 OpCapability Shader
243 OpMemoryModel Logical GLSL450
244 OpEntryPoint Fragment %main "main"
245 OpExecutionMode %main OriginUpperLeft
246 OpExecutionMode %main DepthGreater
247 OpExecutionMode %main DepthLess
248 )" + kVoidFunction;
249 
250   CompileSuccessfully(spirv);
251   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
252   EXPECT_THAT(getDiagnosticString(),
253               HasSubstr("Fragment execution model entry points can specify at "
254                         "most one of DepthGreater, DepthLess or DepthUnchanged "
255                         "execution modes."));
256 }
257 
TEST_F(ValidateMode,FragmentDepthGreaterAndUnchanged)258 TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
259   const std::string spirv = R"(
260 OpCapability Shader
261 OpMemoryModel Logical GLSL450
262 OpEntryPoint Fragment %main "main"
263 OpExecutionMode %main OriginUpperLeft
264 OpExecutionMode %main DepthGreater
265 OpExecutionMode %main DepthUnchanged
266 )" + kVoidFunction;
267 
268   CompileSuccessfully(spirv);
269   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
270   EXPECT_THAT(getDiagnosticString(),
271               HasSubstr("Fragment execution model entry points can specify at "
272                         "most one of DepthGreater, DepthLess or DepthUnchanged "
273                         "execution modes."));
274 }
275 
TEST_F(ValidateMode,FragmentDepthLessAndUnchanged)276 TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
277   const std::string spirv = R"(
278 OpCapability Shader
279 OpMemoryModel Logical GLSL450
280 OpEntryPoint Fragment %main "main"
281 OpExecutionMode %main OriginUpperLeft
282 OpExecutionMode %main DepthLess
283 OpExecutionMode %main DepthUnchanged
284 )" + kVoidFunction;
285 
286   CompileSuccessfully(spirv);
287   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
288   EXPECT_THAT(getDiagnosticString(),
289               HasSubstr("Fragment execution model entry points can specify at "
290                         "most one of DepthGreater, DepthLess or DepthUnchanged "
291                         "execution modes."));
292 }
293 
TEST_F(ValidateMode,FragmentAllDepths)294 TEST_F(ValidateMode, FragmentAllDepths) {
295   const std::string spirv = R"(
296 OpCapability Shader
297 OpMemoryModel Logical GLSL450
298 OpEntryPoint Fragment %main "main"
299 OpExecutionMode %main OriginUpperLeft
300 OpExecutionMode %main DepthGreater
301 OpExecutionMode %main DepthLess
302 OpExecutionMode %main DepthUnchanged
303 )" + kVoidFunction;
304 
305   CompileSuccessfully(spirv);
306   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
307   EXPECT_THAT(getDiagnosticString(),
308               HasSubstr("Fragment execution model entry points can specify at "
309                         "most one of DepthGreater, DepthLess or DepthUnchanged "
310                         "execution modes."));
311 }
312 
TEST_F(ValidateMode,TessellationControlSpacingEqualAndFractionalOdd)313 TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
314   const std::string spirv = R"(
315 OpCapability Tessellation
316 OpMemoryModel Logical GLSL450
317 OpEntryPoint TessellationControl %main "main"
318 OpExecutionMode %main SpacingEqual
319 OpExecutionMode %main SpacingFractionalOdd
320 )" + kVoidFunction;
321 
322   CompileSuccessfully(spirv);
323   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
324   EXPECT_THAT(getDiagnosticString(),
325               HasSubstr("Tessellation execution model entry points can specify "
326                         "at most one of SpacingEqual, SpacingFractionalOdd or "
327                         "SpacingFractionalEven execution modes."));
328 }
329 
TEST_F(ValidateMode,TessellationControlSpacingEqualAndSpacingFractionalEven)330 TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
331   const std::string spirv = R"(
332 OpCapability Tessellation
333 OpMemoryModel Logical GLSL450
334 OpEntryPoint TessellationControl %main "main"
335 OpExecutionMode %main SpacingEqual
336 OpExecutionMode %main SpacingFractionalEven
337 )" + kVoidFunction;
338 
339   CompileSuccessfully(spirv);
340   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
341   EXPECT_THAT(getDiagnosticString(),
342               HasSubstr("Tessellation execution model entry points can specify "
343                         "at most one of SpacingEqual, SpacingFractionalOdd or "
344                         "SpacingFractionalEven execution modes."));
345 }
346 
TEST_F(ValidateMode,TessellationControlSpacingFractionalOddAndSpacingFractionalEven)347 TEST_F(ValidateMode,
348        TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
349   const std::string spirv = R"(
350 OpCapability Tessellation
351 OpMemoryModel Logical GLSL450
352 OpEntryPoint TessellationControl %main "main"
353 OpExecutionMode %main SpacingFractionalOdd
354 OpExecutionMode %main SpacingFractionalEven
355 )" + kVoidFunction;
356 
357   CompileSuccessfully(spirv);
358   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
359   EXPECT_THAT(getDiagnosticString(),
360               HasSubstr("Tessellation execution model entry points can specify "
361                         "at most one of SpacingEqual, SpacingFractionalOdd or "
362                         "SpacingFractionalEven execution modes."));
363 }
364 
TEST_F(ValidateMode,TessellationControlAllSpacing)365 TEST_F(ValidateMode, TessellationControlAllSpacing) {
366   const std::string spirv = R"(
367 OpCapability Tessellation
368 OpMemoryModel Logical GLSL450
369 OpEntryPoint TessellationControl %main "main"
370 OpExecutionMode %main SpacingEqual
371 OpExecutionMode %main SpacingFractionalOdd
372 OpExecutionMode %main SpacingFractionalEven
373 )" + kVoidFunction;
374 
375   CompileSuccessfully(spirv);
376   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
377   EXPECT_THAT(getDiagnosticString(),
378               HasSubstr("Tessellation execution model entry points can specify "
379                         "at most one of SpacingEqual, SpacingFractionalOdd or "
380                         "SpacingFractionalEven execution modes."));
381 }
382 
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalOdd)383 TEST_F(ValidateMode,
384        TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
385   const std::string spirv = R"(
386 OpCapability Tessellation
387 OpMemoryModel Logical GLSL450
388 OpEntryPoint TessellationEvaluation %main "main"
389 OpExecutionMode %main SpacingEqual
390 OpExecutionMode %main SpacingFractionalOdd
391 )" + kVoidFunction;
392 
393   CompileSuccessfully(spirv);
394   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
395   EXPECT_THAT(getDiagnosticString(),
396               HasSubstr("Tessellation execution model entry points can specify "
397                         "at most one of SpacingEqual, SpacingFractionalOdd or "
398                         "SpacingFractionalEven execution modes."));
399 }
400 
TEST_F(ValidateMode,TessellationEvaluationSpacingEqualAndSpacingFractionalEven)401 TEST_F(ValidateMode,
402        TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
403   const std::string spirv = R"(
404 OpCapability Tessellation
405 OpMemoryModel Logical GLSL450
406 OpEntryPoint TessellationEvaluation %main "main"
407 OpExecutionMode %main SpacingEqual
408 OpExecutionMode %main SpacingFractionalEven
409 )" + kVoidFunction;
410 
411   CompileSuccessfully(spirv);
412   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
413   EXPECT_THAT(getDiagnosticString(),
414               HasSubstr("Tessellation execution model entry points can specify "
415                         "at most one of SpacingEqual, SpacingFractionalOdd or "
416                         "SpacingFractionalEven execution modes."));
417 }
418 
TEST_F(ValidateMode,TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven)419 TEST_F(ValidateMode,
420        TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
421   const std::string spirv = R"(
422 OpCapability Tessellation
423 OpMemoryModel Logical GLSL450
424 OpEntryPoint TessellationEvaluation %main "main"
425 OpExecutionMode %main SpacingFractionalOdd
426 OpExecutionMode %main SpacingFractionalEven
427 )" + kVoidFunction;
428 
429   CompileSuccessfully(spirv);
430   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
431   EXPECT_THAT(getDiagnosticString(),
432               HasSubstr("Tessellation execution model entry points can specify "
433                         "at most one of SpacingEqual, SpacingFractionalOdd or "
434                         "SpacingFractionalEven execution modes."));
435 }
436 
TEST_F(ValidateMode,TessellationEvaluationAllSpacing)437 TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
438   const std::string spirv = R"(
439 OpCapability Tessellation
440 OpMemoryModel Logical GLSL450
441 OpEntryPoint TessellationEvaluation %main "main"
442 OpExecutionMode %main SpacingEqual
443 OpExecutionMode %main SpacingFractionalOdd
444 OpExecutionMode %main SpacingFractionalEven
445 )" + kVoidFunction;
446 
447   CompileSuccessfully(spirv);
448   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
449   EXPECT_THAT(getDiagnosticString(),
450               HasSubstr("Tessellation execution model entry points can specify "
451                         "at most one of SpacingEqual, SpacingFractionalOdd or "
452                         "SpacingFractionalEven execution modes."));
453 }
454 
TEST_F(ValidateMode,TessellationControlBothVertex)455 TEST_F(ValidateMode, TessellationControlBothVertex) {
456   const std::string spirv = R"(
457 OpCapability Tessellation
458 OpMemoryModel Logical GLSL450
459 OpEntryPoint TessellationControl %main "main"
460 OpExecutionMode %main VertexOrderCw
461 OpExecutionMode %main VertexOrderCcw
462 )" + kVoidFunction;
463 
464   CompileSuccessfully(spirv);
465   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
466   EXPECT_THAT(
467       getDiagnosticString(),
468       HasSubstr("Tessellation execution model entry points can specify at most "
469                 "one of VertexOrderCw or VertexOrderCcw execution modes."));
470 }
471 
TEST_F(ValidateMode,TessellationEvaluationBothVertex)472 TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
473   const std::string spirv = R"(
474 OpCapability Tessellation
475 OpMemoryModel Logical GLSL450
476 OpEntryPoint TessellationEvaluation %main "main"
477 OpExecutionMode %main VertexOrderCw
478 OpExecutionMode %main VertexOrderCcw
479 )" + kVoidFunction;
480 
481   CompileSuccessfully(spirv);
482   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
483   EXPECT_THAT(
484       getDiagnosticString(),
485       HasSubstr("Tessellation execution model entry points can specify at most "
486                 "one of VertexOrderCw or VertexOrderCcw execution modes."));
487 }
488 
489 using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
490     std::tuple<std::string, std::string, std::string, std::string, std::string>,
491     std::tuple<std::string, std::string, std::string>>>;
492 
TEST_P(ValidateModeGeometry,ExecutionMode)493 TEST_P(ValidateModeGeometry, ExecutionMode) {
494   std::vector<std::string> input_modes;
495   std::vector<std::string> output_modes;
496   input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
497   input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
498   input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
499   input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
500   input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
501   output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
502   output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
503   output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
504 
505   std::ostringstream sstr;
506   sstr << "OpCapability Geometry\n";
507   sstr << "OpMemoryModel Logical GLSL450\n";
508   sstr << "OpEntryPoint Geometry %main \"main\"\n";
509   size_t num_input_modes = 0;
510   for (auto input : input_modes) {
511     if (!input.empty()) {
512       num_input_modes++;
513       sstr << "OpExecutionMode %main " << input << "\n";
514     }
515   }
516   size_t num_output_modes = 0;
517   for (auto output : output_modes) {
518     if (!output.empty()) {
519       num_output_modes++;
520       sstr << "OpExecutionMode %main " << output << "\n";
521     }
522   }
523   sstr << "%void = OpTypeVoid\n";
524   sstr << "%void_fn = OpTypeFunction %void\n";
525   sstr << "%int = OpTypeInt 32 0\n";
526   sstr << "%int1 = OpConstant %int 1\n";
527   sstr << "%main = OpFunction %void None %void_fn\n";
528   sstr << "%entry = OpLabel\n";
529   sstr << "OpReturn\n";
530   sstr << "OpFunctionEnd\n";
531 
532   CompileSuccessfully(sstr.str());
533   if (num_input_modes == 1 && num_output_modes == 1) {
534     EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
535   } else {
536     EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
537     if (num_input_modes != 1) {
538       EXPECT_THAT(getDiagnosticString(),
539                   HasSubstr("Geometry execution model entry points must "
540                             "specify exactly one of InputPoints, InputLines, "
541                             "InputLinesAdjacency, Triangles or "
542                             "InputTrianglesAdjacency execution modes."));
543     } else {
544       EXPECT_THAT(
545           getDiagnosticString(),
546           HasSubstr("Geometry execution model entry points must specify "
547                     "exactly one of OutputPoints, OutputLineStrip or "
548                     "OutputTriangleStrip execution modes."));
549     }
550   }
551 }
552 
553 INSTANTIATE_TEST_SUITE_P(
554     GeometryRequiredModes, ValidateModeGeometry,
555     Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
556                     Values("InputLinesAdjacency", ""), Values("Triangles", ""),
557                     Values("InputTrianglesAdjacency", "")),
558             Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
559                     Values("OutputTriangleStrip", ""))));
560 
561 using ValidateModeExecution =
562     spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
563                                      std::string, spv_target_env>>;
564 
TEST_P(ValidateModeExecution,ExecutionMode)565 TEST_P(ValidateModeExecution, ExecutionMode) {
566   const spv_result_t expectation = std::get<0>(GetParam());
567   const std::string error = std::get<1>(GetParam());
568   const std::string model = std::get<2>(GetParam());
569   const std::string mode = std::get<3>(GetParam());
570   const spv_target_env env = std::get<4>(GetParam());
571 
572   std::ostringstream sstr;
573   sstr << "OpCapability Shader\n";
574   sstr << "OpCapability Geometry\n";
575   sstr << "OpCapability Tessellation\n";
576   sstr << "OpCapability TransformFeedback\n";
577   if (!spvIsVulkanEnv(env)) {
578     sstr << "OpCapability Kernel\n";
579     if (env == SPV_ENV_UNIVERSAL_1_3) {
580       sstr << "OpCapability SubgroupDispatch\n";
581     } else if (env == SPV_ENV_UNIVERSAL_1_5) {
582       sstr << "OpCapability TileImageColorReadAccessEXT\n";
583       sstr << "OpCapability TileImageDepthReadAccessEXT\n";
584       sstr << "OpCapability TileImageStencilReadAccessEXT\n";
585       sstr << "OpExtension \"SPV_EXT_shader_tile_image\"\n";
586     }
587   }
588   sstr << "OpMemoryModel Logical GLSL450\n";
589   sstr << "OpEntryPoint " << model << " %main \"main\"\n";
590   if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
591       mode.find("SubgroupsPerWorkgroupId") == 0) {
592     sstr << "OpExecutionModeId %main " << mode << "\n";
593   } else {
594     sstr << "OpExecutionMode %main " << mode << "\n";
595   }
596   if (model == "Geometry") {
597     if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
598           mode.find("InputLinesAdjacency") == 0 ||
599           mode.find("Triangles") == 0 ||
600           mode.find("InputTrianglesAdjacency") == 0)) {
601       // Exactly one of the above modes is required for Geometry shaders.
602       sstr << "OpExecutionMode %main InputPoints\n";
603     }
604     if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
605           mode.find("OutputTriangleStrip") == 0)) {
606       // Exactly one of the above modes is required for Geometry shaders.
607       sstr << "OpExecutionMode %main OutputPoints\n";
608     }
609   } else if (model == "Fragment") {
610     if (!(mode.find("OriginUpperLeft") == 0 ||
611           mode.find("OriginLowerLeft") == 0)) {
612       // Exactly one of the above modes is required for Fragment shaders.
613       sstr << "OpExecutionMode %main OriginUpperLeft\n";
614     }
615   }
616   sstr << "%void = OpTypeVoid\n";
617   sstr << "%void_fn = OpTypeFunction %void\n";
618   sstr << "%int = OpTypeInt 32 0\n";
619   sstr << "%int1 = OpConstant %int 1\n";
620   sstr << "%main = OpFunction %void None %void_fn\n";
621   sstr << "%entry = OpLabel\n";
622   sstr << "OpReturn\n";
623   sstr << "OpFunctionEnd\n";
624 
625   CompileSuccessfully(sstr.str(), env);
626   EXPECT_THAT(expectation, ValidateInstructions(env));
627   if (expectation != SPV_SUCCESS) {
628     EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
629   }
630 }
631 
632 INSTANTIATE_TEST_SUITE_P(
633     ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
634     Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
635             Values("Invocations 3", "InputPoints", "InputLines",
636                    "InputLinesAdjacency", "InputTrianglesAdjacency",
637                    "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
638             Values(SPV_ENV_UNIVERSAL_1_0)));
639 
640 INSTANTIATE_TEST_SUITE_P(
641     ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
642     Combine(Values(SPV_ERROR_INVALID_DATA),
643             Values("Execution mode can only be used with the Geometry "
644                    "execution model."),
645             Values("Fragment", "TessellationEvaluation", "TessellationControl",
646                    "GLCompute", "Vertex", "Kernel"),
647             Values("Invocations 3", "InputPoints", "InputLines",
648                    "InputLinesAdjacency", "InputTrianglesAdjacency",
649                    "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
650             Values(SPV_ENV_UNIVERSAL_1_0)));
651 
652 INSTANTIATE_TEST_SUITE_P(
653     ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
654     Combine(Values(SPV_SUCCESS), Values(""),
655             Values("TessellationControl", "TessellationEvaluation"),
656             Values("SpacingEqual", "SpacingFractionalEven",
657                    "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
658                    "PointMode", "Quads", "Isolines"),
659             Values(SPV_ENV_UNIVERSAL_1_0)));
660 
661 INSTANTIATE_TEST_SUITE_P(
662     ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
663     Combine(Values(SPV_ERROR_INVALID_DATA),
664             Values("Execution mode can only be used with a tessellation "
665                    "execution model."),
666             Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
667             Values("SpacingEqual", "SpacingFractionalEven",
668                    "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
669                    "PointMode", "Quads", "Isolines"),
670             Values(SPV_ENV_UNIVERSAL_1_0)));
671 
672 INSTANTIATE_TEST_SUITE_P(ValidateModeGeometryAndTessellationGoodSpv10,
673                          ValidateModeExecution,
674                          Combine(Values(SPV_SUCCESS), Values(""),
675                                  Values("TessellationControl",
676                                         "TessellationEvaluation", "Geometry"),
677                                  Values("Triangles", "OutputVertices 3"),
678                                  Values(SPV_ENV_UNIVERSAL_1_0)));
679 
680 INSTANTIATE_TEST_SUITE_P(
681     ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
682     Combine(Values(SPV_ERROR_INVALID_DATA),
683             Values("Execution mode can only be used with a Geometry or "
684                    "tessellation execution model."),
685             Values("Fragment", "GLCompute", "Vertex", "Kernel"),
686             Values("Triangles", "OutputVertices 3"),
687             Values(SPV_ENV_UNIVERSAL_1_0)));
688 
689 INSTANTIATE_TEST_SUITE_P(
690     ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
691     Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
692             Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
693                    "EarlyFragmentTests", "DepthReplacing", "DepthLess",
694                    "DepthUnchanged"),
695             Values(SPV_ENV_UNIVERSAL_1_0)));
696 
697 INSTANTIATE_TEST_SUITE_P(
698     ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
699     Combine(Values(SPV_ERROR_INVALID_DATA),
700             Values("Execution mode can only be used with the Fragment "
701                    "execution model."),
702             Values("Geometry", "TessellationControl", "TessellationEvaluation",
703                    "GLCompute", "Vertex", "Kernel"),
704             Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
705                    "EarlyFragmentTests", "DepthReplacing", "DepthGreater",
706                    "DepthLess", "DepthUnchanged"),
707             Values(SPV_ENV_UNIVERSAL_1_0)));
708 
709 INSTANTIATE_TEST_SUITE_P(ValidateModeFragmentOnlyGoodSpv15,
710                          ValidateModeExecution,
711                          Combine(Values(SPV_SUCCESS), Values(""),
712                                  Values("Fragment"),
713                                  Values("NonCoherentColorAttachmentReadEXT",
714                                         "NonCoherentDepthAttachmentReadEXT",
715                                         "NonCoherentStencilAttachmentReadEXT"),
716                                  Values(SPV_ENV_UNIVERSAL_1_5)));
717 
718 INSTANTIATE_TEST_SUITE_P(
719     ValidateModeFragmentOnlyBadSpv15, ValidateModeExecution,
720     Combine(Values(SPV_ERROR_INVALID_DATA),
721             Values("Execution mode can only be used with the Fragment "
722                    "execution model."),
723             Values("Geometry", "TessellationControl", "TessellationEvaluation",
724                    "GLCompute", "Vertex", "Kernel"),
725             Values("NonCoherentColorAttachmentReadEXT",
726                    "NonCoherentDepthAttachmentReadEXT",
727                    "NonCoherentStencilAttachmentReadEXT"),
728             Values(SPV_ENV_UNIVERSAL_1_5)));
729 
730 INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
731                          Combine(Values(SPV_SUCCESS), Values(""),
732                                  Values("Kernel"),
733                                  Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
734                                         "ContractionOff",
735                                         "LocalSizeHintId %int1 %int1 %int1"),
736                                  Values(SPV_ENV_UNIVERSAL_1_3)));
737 
738 INSTANTIATE_TEST_SUITE_P(
739     ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
740     Combine(
741         Values(SPV_ERROR_INVALID_DATA),
742         Values(
743             "Execution mode can only be used with the Kernel execution model."),
744         Values("Geometry", "TessellationControl", "TessellationEvaluation",
745                "GLCompute", "Vertex", "Fragment"),
746         Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
747                "LocalSizeHintId %int1 %int1 %int1"),
748         Values(SPV_ENV_UNIVERSAL_1_3)));
749 
750 INSTANTIATE_TEST_SUITE_P(
751     ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
752     Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
753             Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
754             Values(SPV_ENV_UNIVERSAL_1_3)));
755 
756 INSTANTIATE_TEST_SUITE_P(
757     ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
758     Combine(Values(SPV_ERROR_INVALID_DATA),
759             Values("Execution mode can only be used with a Kernel or GLCompute "
760                    "execution model."),
761             Values("Geometry", "TessellationControl", "TessellationEvaluation",
762                    "Fragment", "Vertex"),
763             Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
764             Values(SPV_ENV_UNIVERSAL_1_3)));
765 
766 INSTANTIATE_TEST_SUITE_P(
767     ValidateModeAllGoodSpv13, ValidateModeExecution,
768     Combine(Values(SPV_SUCCESS), Values(""),
769             Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
770                    "TessellationEvaluation", "Fragment", "Vertex"),
771             Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
772                    "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
773             Values(SPV_ENV_UNIVERSAL_1_3)));
774 
TEST_F(ValidateModeExecution,MeshNVLocalSize)775 TEST_F(ValidateModeExecution, MeshNVLocalSize) {
776   const std::string spirv = R"(
777 OpCapability Shader
778 OpCapability MeshShadingNV
779 OpExtension "SPV_NV_mesh_shader"
780 OpMemoryModel Logical GLSL450
781 OpEntryPoint MeshNV %main "main"
782 OpExecutionMode %main LocalSize 1 1 1
783 )" + kVoidFunction;
784 
785   CompileSuccessfully(spirv);
786   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
787 }
788 
TEST_F(ValidateModeExecution,TaskNVLocalSize)789 TEST_F(ValidateModeExecution, TaskNVLocalSize) {
790   const std::string spirv = R"(
791 OpCapability Shader
792 OpCapability MeshShadingNV
793 OpExtension "SPV_NV_mesh_shader"
794 OpMemoryModel Logical GLSL450
795 OpEntryPoint TaskNV %main "main"
796 OpExecutionMode %main LocalSize 1 1 1
797 )" + kVoidFunction;
798 
799   CompileSuccessfully(spirv);
800   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
801 }
802 
TEST_F(ValidateModeExecution,MeshNVOutputPoints)803 TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
804   const std::string spirv = R"(
805 OpCapability Shader
806 OpCapability MeshShadingNV
807 OpExtension "SPV_NV_mesh_shader"
808 OpMemoryModel Logical GLSL450
809 OpEntryPoint MeshNV %main "main"
810 OpExecutionMode %main OutputPoints
811 )" + kVoidFunction;
812 
813   CompileSuccessfully(spirv);
814   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
815 }
816 
TEST_F(ValidateModeExecution,MeshNVOutputVertices)817 TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
818   const std::string spirv = R"(
819 OpCapability Shader
820 OpCapability MeshShadingNV
821 OpExtension "SPV_NV_mesh_shader"
822 OpMemoryModel Logical GLSL450
823 OpEntryPoint MeshNV %main "main"
824 OpExecutionMode %main OutputVertices 42
825 )" + kVoidFunction;
826 
827   CompileSuccessfully(spirv);
828   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
829 }
830 
TEST_F(ValidateModeExecution,MeshNVLocalSizeId)831 TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
832   const std::string spirv = R"(
833 OpCapability Shader
834 OpCapability MeshShadingNV
835 OpExtension "SPV_NV_mesh_shader"
836 OpMemoryModel Logical GLSL450
837 OpEntryPoint MeshNV %main "main"
838 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
839 %int = OpTypeInt 32 0
840 %int_1 = OpConstant %int 1
841 )" + kVoidFunction;
842 
843   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
844   CompileSuccessfully(spirv, env);
845   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
846 }
847 
TEST_F(ValidateModeExecution,TaskNVLocalSizeId)848 TEST_F(ValidateModeExecution, TaskNVLocalSizeId) {
849   const std::string spirv = R"(
850 OpCapability Shader
851 OpCapability MeshShadingNV
852 OpExtension "SPV_NV_mesh_shader"
853 OpMemoryModel Logical GLSL450
854 OpEntryPoint TaskNV %main "main"
855 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
856 %int = OpTypeInt 32 0
857 %int_1 = OpConstant %int 1
858 )" + kVoidFunction;
859 
860   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
861   CompileSuccessfully(spirv, env);
862   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
863 }
864 
TEST_F(ValidateModeExecution,ExecModeSubgroupsPerWorkgroupIdBad)865 TEST_F(ValidateModeExecution, ExecModeSubgroupsPerWorkgroupIdBad) {
866   const std::string spirv = R"(
867 OpCapability Shader
868 OpCapability SubgroupDispatch
869 OpMemoryModel Logical GLSL450
870 OpEntryPoint Vertex %main "main"
871 OpExecutionMode %main SubgroupsPerWorkgroupId %int_1
872 %int = OpTypeInt 32 0
873 %int_1 = OpConstant %int 1
874 )" + kVoidFunction;
875 
876   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
877   CompileSuccessfully(spirv, env);
878   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
879   EXPECT_THAT(getDiagnosticString(),
880               HasSubstr("OpExecutionMode is only valid when the Mode operand "
881                         "is an execution mode that takes no Extra Operands"));
882 }
883 
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdGood)884 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdGood) {
885   const std::string spirv = R"(
886 OpCapability Shader
887 OpCapability SubgroupDispatch
888 OpMemoryModel Logical GLSL450
889 OpEntryPoint Vertex %main "main"
890 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
891 %int = OpTypeInt 32 0
892 %int_1 = OpConstant %int 1
893 )" + kVoidFunction;
894 
895   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
896   CompileSuccessfully(spirv, env);
897   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
898 }
899 
TEST_F(ValidateModeExecution,ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad)900 TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad) {
901   const std::string spirv = R"(
902 OpCapability Shader
903 OpCapability SubgroupDispatch
904 OpMemoryModel Logical GLSL450
905 OpEntryPoint Vertex %main "main"
906 OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1
907 %int = OpTypeInt 32 0
908 %int_ptr = OpTypePointer Private %int
909 %int_1 = OpVariable %int_ptr Private
910 )" + kVoidFunction;
911 
912   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
913   CompileSuccessfully(spirv, env);
914   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
915   EXPECT_THAT(getDiagnosticString(),
916               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
917                         "constant instructions."));
918 }
919 
TEST_F(ValidateModeExecution,ExecModeLocalSizeHintIdBad)920 TEST_F(ValidateModeExecution, ExecModeLocalSizeHintIdBad) {
921   const std::string spirv = R"(
922 OpCapability Kernel
923 OpCapability Shader
924 OpMemoryModel Logical GLSL450
925 OpEntryPoint Kernel %main "main"
926 OpExecutionMode %main LocalSizeHintId %int_1 %int_1 %int_1
927 %int = OpTypeInt 32 0
928 %int_1 = OpConstant %int 1
929 )" + kVoidFunction;
930 
931   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
932   CompileSuccessfully(spirv, env);
933   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
934   EXPECT_THAT(getDiagnosticString(),
935               HasSubstr("OpExecutionMode is only valid when the Mode operand "
936                         "is an execution mode that takes no Extra Operands"));
937 }
938 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdGood)939 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdGood) {
940   const std::string spirv = R"(
941 OpCapability Kernel
942 OpCapability Shader
943 OpMemoryModel Logical GLSL450
944 OpEntryPoint Kernel %main "main"
945 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
946 %int = OpTypeInt 32 0
947 %int_1 = OpConstant %int 1
948 )" + kVoidFunction;
949 
950   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
951   CompileSuccessfully(spirv, env);
952   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
953 }
954 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeHintIdNonConstantBad)955 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdNonConstantBad) {
956   const std::string spirv = R"(
957 OpCapability Kernel
958 OpCapability Shader
959 OpMemoryModel Logical GLSL450
960 OpEntryPoint Vertex %main "main"
961 OpExecutionModeId %main LocalSizeHintId %int_1 %int_1 %int_1
962 %int = OpTypeInt 32 0
963 %int_ptr = OpTypePointer Private %int
964 %int_1 = OpVariable %int_ptr Private
965 )" + kVoidFunction;
966 
967   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
968   CompileSuccessfully(spirv, env);
969   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
970   EXPECT_THAT(getDiagnosticString(),
971               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
972                         "constant instructions."));
973 }
974 
TEST_F(ValidateModeExecution,ExecModeLocalSizeIdBad)975 TEST_F(ValidateModeExecution, ExecModeLocalSizeIdBad) {
976   const std::string spirv = R"(
977 OpCapability Kernel
978 OpCapability Shader
979 OpMemoryModel Logical GLSL450
980 OpEntryPoint Kernel %main "main"
981 OpExecutionMode %main LocalSizeId %int_1 %int_1 %int_1
982 %int = OpTypeInt 32 0
983 %int_1 = OpConstant %int 1
984 )" + kVoidFunction;
985 
986   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
987   CompileSuccessfully(spirv, env);
988   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
989   EXPECT_THAT(getDiagnosticString(),
990               HasSubstr("OpExecutionMode is only valid when the Mode operand "
991                         "is an execution mode that takes no Extra Operands"));
992 }
993 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdGood)994 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdGood) {
995   const std::string spirv = R"(
996 OpCapability Kernel
997 OpCapability Shader
998 OpMemoryModel Logical GLSL450
999 OpEntryPoint Kernel %main "main"
1000 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
1001 %int = OpTypeInt 32 0
1002 %int_1 = OpConstant %int 1
1003 )" + kVoidFunction;
1004 
1005   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
1006   CompileSuccessfully(spirv, env);
1007   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
1008 }
1009 
TEST_F(ValidateModeExecution,ExecModeIdLocalSizeIdNonConstantBad)1010 TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdNonConstantBad) {
1011   const std::string spirv = R"(
1012 OpCapability Kernel
1013 OpCapability Shader
1014 OpMemoryModel Logical GLSL450
1015 OpEntryPoint Vertex %main "main"
1016 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
1017 %int = OpTypeInt 32 0
1018 %int_ptr = OpTypePointer Private %int
1019 %int_1 = OpVariable %int_ptr Private
1020 )" + kVoidFunction;
1021 
1022   spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
1023   CompileSuccessfully(spirv, env);
1024   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env));
1025   EXPECT_THAT(getDiagnosticString(),
1026               HasSubstr("For OpExecutionModeId all Extra Operand ids must be "
1027                         "constant instructions."));
1028 }
1029 
1030 using AllowMultipleExecutionModes = spvtest::ValidateBase<std::string>;
1031 
TEST_P(AllowMultipleExecutionModes,DifferentOperand)1032 TEST_P(AllowMultipleExecutionModes, DifferentOperand) {
1033   const std::string mode = GetParam();
1034   const std::string spirv = R"(
1035 OpCapability Shader
1036 OpCapability DenormPreserve
1037 OpCapability DenormFlushToZero
1038 OpCapability SignedZeroInfNanPreserve
1039 OpCapability RoundingModeRTE
1040 OpCapability RoundingModeRTZ
1041 OpExtension "SPV_KHR_float_controls"
1042 OpMemoryModel Logical GLSL450
1043 OpEntryPoint GLCompute %main "main"
1044 OpExecutionMode %main LocalSize 1 1 1
1045 OpExecutionMode %main )" + mode +
1046                             R"( 16
1047 OpExecutionMode %main )" + mode +
1048                             R"( 32
1049 %void = OpTypeVoid
1050 %void_fn = OpTypeFunction %void
1051 %main = OpFunction %void None %void_fn
1052 %entry = OpLabel
1053 OpReturn
1054 OpFunctionEnd
1055 )";
1056 
1057   CompileSuccessfully(spirv);
1058   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
1059 }
1060 
TEST_P(AllowMultipleExecutionModes,SameOperand)1061 TEST_P(AllowMultipleExecutionModes, SameOperand) {
1062   const std::string mode = GetParam();
1063   const std::string spirv = R"(
1064 OpCapability Shader
1065 OpCapability DenormPreserve
1066 OpCapability DenormFlushToZero
1067 OpCapability SignedZeroInfNanPreserve
1068 OpCapability RoundingModeRTE
1069 OpCapability RoundingModeRTZ
1070 OpExtension "SPV_KHR_float_controls"
1071 OpMemoryModel Logical GLSL450
1072 OpEntryPoint GLCompute %main "main"
1073 OpExecutionMode %main LocalSize 1 1 1
1074 OpExecutionMode %main )" + mode +
1075                             R"( 32
1076 OpExecutionMode %main )" + mode +
1077                             R"( 32
1078 %void = OpTypeVoid
1079 %void_fn = OpTypeFunction %void
1080 %main = OpFunction %void None %void_fn
1081 %entry = OpLabel
1082 OpReturn
1083 OpFunctionEnd
1084 )";
1085 
1086   CompileSuccessfully(spirv);
1087   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1088   EXPECT_THAT(getDiagnosticString(),
1089               HasSubstr("execution mode must not be specified multiple times "
1090                         "for the same entry point and operands"));
1091 }
1092 
1093 INSTANTIATE_TEST_SUITE_P(MultipleFloatControlsExecModes,
1094                          AllowMultipleExecutionModes,
1095                          Values("DenormPreserve", "DenormFlushToZero",
1096                                 "SignedZeroInfNanPreserve", "RoundingModeRTE",
1097                                 "RoundingModeRTZ"));
1098 
1099 using MultipleExecModes = spvtest::ValidateBase<std::string>;
1100 
TEST_P(MultipleExecModes,DuplicateMode)1101 TEST_P(MultipleExecModes, DuplicateMode) {
1102   const std::string mode = GetParam();
1103   const std::string spirv = R"(
1104 OpCapability Shader
1105 OpMemoryModel Logical GLSL450
1106 OpEntryPoint Fragment %main "main"
1107 OpExecutionMode %main OriginUpperLeft
1108 OpExecutionMode %main )" + mode +
1109                             R"(
1110 OpExecutionMode %main )" + mode +
1111                             R"(
1112 %void = OpTypeVoid
1113 %void_fn = OpTypeFunction %void
1114 %main = OpFunction %void None %void_fn
1115 %entry = OpLabel
1116 OpReturn
1117 OpFunctionEnd
1118 )";
1119 
1120   CompileSuccessfully(spirv);
1121   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
1122   EXPECT_THAT(getDiagnosticString(),
1123               HasSubstr("execution mode must not be specified multiple times "
1124                         "per entry point"));
1125 }
1126 
1127 INSTANTIATE_TEST_SUITE_P(MultipleFragmentExecMode, MultipleExecModes,
1128                          Values("DepthReplacing", "DepthGreater", "DepthLess",
1129                                 "DepthUnchanged"));
1130 
TEST_F(ValidateMode,FloatControls2FPFastMathDefaultSameOperand)1131 TEST_F(ValidateMode, FloatControls2FPFastMathDefaultSameOperand) {
1132   const std::string spirv = R"(
1133 OpCapability Shader
1134 OpCapability FloatControls2
1135 OpExtension "SPV_KHR_float_controls2"
1136 OpMemoryModel Logical GLSL450
1137 OpEntryPoint GLCompute %main "main"
1138 OpExecutionMode %main LocalSize 1 1 1
1139 OpExecutionModeId %main FPFastMathDefault %float %none
1140 OpExecutionModeId %main FPFastMathDefault %float %none
1141 %void = OpTypeVoid
1142 %float = OpTypeFloat 32
1143 %int = OpTypeInt 32 0
1144 %none = OpConstant %int 0
1145 %void_fn = OpTypeFunction %void
1146 %main = OpFunction %void None %void_fn
1147 %entry = OpLabel
1148 OpReturn
1149 OpFunctionEnd
1150 )";
1151 
1152   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
1153   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
1154   EXPECT_THAT(getDiagnosticString(),
1155               HasSubstr("execution mode must not be specified multiple times "
1156                         "for the same entry point and operands"));
1157 }
1158 
TEST_F(ValidateMode,FloatControls2FPFastMathDefaultDifferentOperand)1159 TEST_F(ValidateMode, FloatControls2FPFastMathDefaultDifferentOperand) {
1160   const std::string spirv = R"(
1161 OpCapability Shader
1162 OpCapability Float16
1163 OpCapability FloatControls2
1164 OpExtension "SPV_KHR_float_controls2"
1165 OpMemoryModel Logical GLSL450
1166 OpEntryPoint GLCompute %main "main"
1167 OpExecutionMode %main LocalSize 1 1 1
1168 OpExecutionModeId %main FPFastMathDefault %float %none
1169 OpExecutionModeId %main FPFastMathDefault %half %none
1170 %void = OpTypeVoid
1171 %float = OpTypeFloat 32
1172 %int = OpTypeInt 32 0
1173 %none = OpConstant %int 0
1174 %half = OpTypeFloat 16
1175 %void_fn = OpTypeFunction %void
1176 %main = OpFunction %void None %void_fn
1177 %entry = OpLabel
1178 OpReturn
1179 OpFunctionEnd
1180 )";
1181 
1182   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2);
1183   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2));
1184 }
1185 
TEST_F(ValidateMode,FragmentShaderInterlockVertexBad)1186 TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) {
1187   const std::string spirv = R"(
1188 OpCapability Shader
1189 OpCapability FragmentShaderPixelInterlockEXT
1190 OpExtension "SPV_EXT_fragment_shader_interlock"
1191 OpMemoryModel Logical GLSL450
1192 OpEntryPoint Vertex %main "main"
1193 OpExecutionMode %main PixelInterlockOrderedEXT
1194 )" + kVoidFunction;
1195 
1196   CompileSuccessfully(spirv);
1197   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1198   EXPECT_THAT(
1199       getDiagnosticString(),
1200       HasSubstr(
1201           "Execution mode can only be used with the Fragment execution model"));
1202 }
1203 
TEST_F(ValidateMode,FragmentShaderInterlockTooManyModesBad)1204 TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) {
1205   const std::string spirv = R"(
1206 OpCapability Shader
1207 OpCapability FragmentShaderPixelInterlockEXT
1208 OpCapability FragmentShaderSampleInterlockEXT
1209 OpExtension "SPV_EXT_fragment_shader_interlock"
1210 OpMemoryModel Logical GLSL450
1211 OpEntryPoint Fragment %main "main"
1212 OpExecutionMode %main OriginUpperLeft
1213 OpExecutionMode %main PixelInterlockOrderedEXT
1214 OpExecutionMode %main SampleInterlockOrderedEXT
1215 )" + kVoidFunction;
1216 
1217   CompileSuccessfully(spirv);
1218   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1219   EXPECT_THAT(
1220       getDiagnosticString(),
1221       HasSubstr("Fragment execution model entry points can specify at most "
1222                 "one fragment shader interlock execution mode"));
1223 }
1224 
TEST_F(ValidateMode,FragmentShaderInterlockNoModeBad)1225 TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) {
1226   const std::string spirv = R"(
1227 OpCapability Shader
1228 OpCapability FragmentShaderPixelInterlockEXT
1229 OpExtension "SPV_EXT_fragment_shader_interlock"
1230 OpMemoryModel Logical GLSL450
1231 OpEntryPoint Fragment %main "main"
1232 OpExecutionMode %main OriginUpperLeft
1233 %void = OpTypeVoid
1234 %void_fn = OpTypeFunction %void
1235 %func = OpFunction %void None %void_fn
1236 %entryf = OpLabel
1237 OpBeginInvocationInterlockEXT
1238 OpEndInvocationInterlockEXT
1239 OpReturn
1240 OpFunctionEnd
1241 %main = OpFunction %void None %void_fn
1242 %entry = OpLabel
1243 %1 = OpFunctionCall %void %func
1244 OpReturn
1245 OpFunctionEnd
1246 )";
1247 
1248   CompileSuccessfully(spirv);
1249   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1250   EXPECT_THAT(
1251       getDiagnosticString(),
1252       HasSubstr(
1253           "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a "
1254           "fragment shader interlock execution mode"));
1255 }
1256 
TEST_F(ValidateMode,FragmentShaderInterlockGood)1257 TEST_F(ValidateMode, FragmentShaderInterlockGood) {
1258   const std::string spirv = R"(
1259 OpCapability Shader
1260 OpCapability FragmentShaderPixelInterlockEXT
1261 OpExtension "SPV_EXT_fragment_shader_interlock"
1262 OpMemoryModel Logical GLSL450
1263 OpEntryPoint Fragment %main "main"
1264 OpExecutionMode %main OriginUpperLeft
1265 OpExecutionMode %main PixelInterlockOrderedEXT
1266 %void = OpTypeVoid
1267 %void_fn = OpTypeFunction %void
1268 %func = OpFunction %void None %void_fn
1269 %entryf = OpLabel
1270 OpBeginInvocationInterlockEXT
1271 OpEndInvocationInterlockEXT
1272 OpReturn
1273 OpFunctionEnd
1274 %main = OpFunction %void None %void_fn
1275 %entry = OpLabel
1276 %1 = OpFunctionCall %void %func
1277 OpReturn
1278 OpFunctionEnd
1279 )";
1280 
1281   CompileSuccessfully(spirv);
1282   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1283 }
1284 
1285 
TEST_F(ValidateMode,FragmentShaderStencilRefFrontTooManyModesBad)1286 TEST_F(ValidateMode, FragmentShaderStencilRefFrontTooManyModesBad) {
1287   const std::string spirv = R"(
1288 OpCapability Shader
1289 OpCapability StencilExportEXT
1290 OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
1291 OpExtension "SPV_EXT_shader_stencil_export"
1292 OpMemoryModel Logical GLSL450
1293 OpEntryPoint Fragment %main "main"
1294 OpExecutionMode %main OriginUpperLeft
1295 OpExecutionMode %main EarlyAndLateFragmentTestsAMD
1296 OpExecutionMode %main StencilRefLessFrontAMD
1297 OpExecutionMode %main StencilRefGreaterFrontAMD
1298 )" + kVoidFunction;
1299 
1300   CompileSuccessfully(spirv);
1301   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1302   EXPECT_THAT(
1303       getDiagnosticString(),
1304       HasSubstr("Fragment execution model entry points can specify at most "
1305                 "one of StencilRefUnchangedFrontAMD, "
1306                 "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
1307                 "execution modes."));
1308 }
1309 
TEST_F(ValidateMode,FragmentShaderStencilRefBackTooManyModesBad)1310 TEST_F(ValidateMode, FragmentShaderStencilRefBackTooManyModesBad) {
1311   const std::string spirv = R"(
1312 OpCapability Shader
1313 OpCapability StencilExportEXT
1314 OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
1315 OpExtension "SPV_EXT_shader_stencil_export"
1316 OpMemoryModel Logical GLSL450
1317 OpEntryPoint Fragment %main "main"
1318 OpExecutionMode %main OriginUpperLeft
1319 OpExecutionMode %main EarlyAndLateFragmentTestsAMD
1320 OpExecutionMode %main StencilRefLessBackAMD
1321 OpExecutionMode %main StencilRefGreaterBackAMD
1322 )" + kVoidFunction;
1323 
1324   CompileSuccessfully(spirv);
1325   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1326   EXPECT_THAT(
1327       getDiagnosticString(),
1328       HasSubstr("Fragment execution model entry points can specify at most "
1329                 "one of StencilRefUnchangedBackAMD, "
1330                 "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
1331                 "execution modes."));
1332 }
1333 
TEST_F(ValidateMode,FragmentShaderStencilRefFrontGood)1334 TEST_F(ValidateMode, FragmentShaderStencilRefFrontGood) {
1335   const std::string spirv = R"(
1336 OpCapability Shader
1337 OpCapability StencilExportEXT
1338 OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
1339 OpExtension "SPV_EXT_shader_stencil_export"
1340 OpMemoryModel Logical GLSL450
1341 OpEntryPoint Fragment %main "main"
1342 OpExecutionMode %main OriginUpperLeft
1343 OpExecutionMode %main EarlyAndLateFragmentTestsAMD
1344 OpExecutionMode %main StencilRefLessFrontAMD
1345 )" + kVoidFunction;
1346 
1347   CompileSuccessfully(spirv);
1348   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1349 }
1350 
TEST_F(ValidateMode,FragmentShaderStencilRefBackGood)1351 TEST_F(ValidateMode, FragmentShaderStencilRefBackGood) {
1352   const std::string spirv = R"(
1353 OpCapability Shader
1354 OpCapability StencilExportEXT
1355 OpExtension "SPV_AMD_shader_early_and_late_fragment_tests"
1356 OpExtension "SPV_EXT_shader_stencil_export"
1357 OpMemoryModel Logical GLSL450
1358 OpEntryPoint Fragment %main "main"
1359 OpExecutionMode %main OriginUpperLeft
1360 OpExecutionMode %main EarlyAndLateFragmentTestsAMD
1361 OpExecutionMode %main StencilRefLessBackAMD
1362 )" + kVoidFunction;
1363 
1364   CompileSuccessfully(spirv);
1365   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1366 }
1367 
TEST_F(ValidateMode,FragmentShaderDemoteVertexBad)1368 TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) {
1369   const std::string spirv = R"(
1370 OpCapability Shader
1371 OpCapability DemoteToHelperInvocationEXT
1372 OpExtension "SPV_EXT_demote_to_helper_invocation"
1373 OpMemoryModel Logical GLSL450
1374 OpEntryPoint Vertex %main "main"
1375 %bool = OpTypeBool
1376 %void = OpTypeVoid
1377 %void_fn = OpTypeFunction %void
1378 %main = OpFunction %void None %void_fn
1379 %entry = OpLabel
1380 OpDemoteToHelperInvocationEXT
1381 %1 = OpIsHelperInvocationEXT %bool
1382 OpReturn
1383 OpFunctionEnd
1384 )";
1385 
1386   CompileSuccessfully(spirv);
1387   EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions());
1388   EXPECT_THAT(
1389       getDiagnosticString(),
1390       HasSubstr(
1391           "OpDemoteToHelperInvocationEXT requires Fragment execution model"));
1392   EXPECT_THAT(
1393       getDiagnosticString(),
1394       HasSubstr("OpIsHelperInvocationEXT requires Fragment execution model"));
1395 }
1396 
TEST_F(ValidateMode,FragmentShaderDemoteGood)1397 TEST_F(ValidateMode, FragmentShaderDemoteGood) {
1398   const std::string spirv = R"(
1399 OpCapability Shader
1400 OpCapability DemoteToHelperInvocationEXT
1401 OpExtension "SPV_EXT_demote_to_helper_invocation"
1402 OpMemoryModel Logical GLSL450
1403 OpEntryPoint Fragment %main "main"
1404 OpExecutionMode %main OriginUpperLeft
1405 %bool = OpTypeBool
1406 %void = OpTypeVoid
1407 %void_fn = OpTypeFunction %void
1408 %main = OpFunction %void None %void_fn
1409 %entry = OpLabel
1410 OpDemoteToHelperInvocationEXT
1411 %1 = OpIsHelperInvocationEXT %bool
1412 OpReturn
1413 OpFunctionEnd
1414 )";
1415 
1416   CompileSuccessfully(spirv);
1417   EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
1418 }
1419 
TEST_F(ValidateMode,FragmentShaderDemoteBadType)1420 TEST_F(ValidateMode, FragmentShaderDemoteBadType) {
1421   const std::string spirv = R"(
1422 OpCapability Shader
1423 OpCapability DemoteToHelperInvocationEXT
1424 OpExtension "SPV_EXT_demote_to_helper_invocation"
1425 OpMemoryModel Logical GLSL450
1426 OpEntryPoint Fragment %main "main"
1427 OpExecutionMode %main OriginUpperLeft
1428 %u32 = OpTypeInt 32 0
1429 %void = OpTypeVoid
1430 %void_fn = OpTypeFunction %void
1431 %main = OpFunction %void None %void_fn
1432 %entry = OpLabel
1433 OpDemoteToHelperInvocationEXT
1434 %1 = OpIsHelperInvocationEXT %u32
1435 OpReturn
1436 OpFunctionEnd
1437 )";
1438 
1439   CompileSuccessfully(spirv);
1440   EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1441   EXPECT_THAT(getDiagnosticString(),
1442               HasSubstr("Expected bool scalar type as Result Type"));
1443 }
1444 
TEST_F(ValidateMode,LocalSizeIdVulkan1p3DoesNotRequireOption)1445 TEST_F(ValidateMode, LocalSizeIdVulkan1p3DoesNotRequireOption) {
1446   const std::string spirv = R"(
1447 OpCapability Shader
1448 OpMemoryModel Logical GLSL450
1449 OpEntryPoint GLCompute %main "main"
1450 OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
1451 %void = OpTypeVoid
1452 %int = OpTypeInt 32 0
1453 %int_1 = OpConstant %int 1
1454 %void_fn = OpTypeFunction %void
1455 %main = OpFunction %void None %void_fn
1456 %entry = OpLabel
1457 OpReturn
1458 OpFunctionEnd
1459 )";
1460 
1461   CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3);
1462   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
1463 }
1464 
TEST_F(ValidateMode,MaximalReconvergenceRequiresExtension)1465 TEST_F(ValidateMode, MaximalReconvergenceRequiresExtension) {
1466   const std::string spirv = R"(
1467 OpCapability Shader
1468 OpMemoryModel Logical GLSL450
1469 OpEntryPoint GLCompute %main "main"
1470 OpExecutionMode %main LocalSize 1 1 1
1471 OpExecutionMode %main MaximallyReconvergesKHR
1472 %void = OpTypeVoid
1473 %void_fn = OpTypeFunction %void
1474 %main = OpFunction %void None %void_fn
1475 %entry = OpLabel
1476 OpReturn
1477 OpFunctionEnd
1478 )";
1479 
1480   CompileSuccessfully(spirv);
1481   EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions());
1482   EXPECT_THAT(getDiagnosticString(),
1483               HasSubstr("(6023) requires one of these extensions: "
1484                         "SPV_KHR_maximal_reconvergence "));
1485 }
1486 
TEST_F(ValidateMode,FPFastMathDefaultNotExecutionModeId)1487 TEST_F(ValidateMode, FPFastMathDefaultNotExecutionModeId) {
1488   const std::string spirv = R"(
1489 OpCapability Shader
1490 OpCapability FloatControls2
1491 OpExtension "SPV_KHR_float_controls2"
1492 OpMemoryModel Logical GLSL450
1493 OpEntryPoint GLCompute %main "main"
1494 OpExecutionMode %main LocalSize 1 1 1
1495 OpExecutionMode %main FPFastMathDefault %int_0 %int_0
1496 %void = OpTypeVoid
1497 %int = OpTypeInt 32 0
1498 %int_0 = OpConstant %int 0
1499 %void_fn = OpTypeFunction %void
1500 %main = OpFunction %void None %void_fn
1501 %entry = OpLabel
1502 OpReturn
1503 OpFunctionEnd
1504 )";
1505 
1506   CompileSuccessfully(spirv);
1507   EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
1508   EXPECT_THAT(getDiagnosticString(),
1509               HasSubstr("OpExecutionMode is only valid when the Mode operand "
1510                         "is an execution mode that takes no Extra Operands, or "
1511                         "takes Extra Operands that are not id operands"));
1512 }
1513 
TEST_F(ValidateMode,FPFastMathDefaultNotAType)1514 TEST_F(ValidateMode, FPFastMathDefaultNotAType) {
1515   const std::string spirv = R"(
1516 OpCapability Shader
1517 OpCapability FloatControls2
1518 OpExtension "SPV_KHR_float_controls2"
1519 OpMemoryModel Logical GLSL450
1520 OpEntryPoint GLCompute %main "main"
1521 OpExecutionMode %main LocalSize 1 1 1
1522 OpExecutionModeId %main FPFastMathDefault %int_0 %int_0
1523 %void = OpTypeVoid
1524 %int = OpTypeInt 32 0
1525 %int_0 = OpConstant %int 0
1526 %void_fn = OpTypeFunction %void
1527 %main = OpFunction %void None %void_fn
1528 %entry = OpLabel
1529 OpReturn
1530 OpFunctionEnd
1531 )";
1532 
1533   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1534   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1535   EXPECT_THAT(
1536       getDiagnosticString(),
1537       HasSubstr(
1538           "The Target Type operand must be a floating-point scalar type"));
1539 }
1540 
TEST_F(ValidateMode,FPFastMathDefaultNotAFloatType)1541 TEST_F(ValidateMode, FPFastMathDefaultNotAFloatType) {
1542   const std::string spirv = R"(
1543 OpCapability Shader
1544 OpCapability FloatControls2
1545 OpExtension "SPV_KHR_float_controls2"
1546 OpMemoryModel Logical GLSL450
1547 OpEntryPoint GLCompute %main "main"
1548 OpExecutionMode %main LocalSize 1 1 1
1549 OpExecutionModeId %main FPFastMathDefault %int %int_0
1550 %void = OpTypeVoid
1551 %int = OpTypeInt 32 0
1552 %int_0 = OpConstant %int 0
1553 %void_fn = OpTypeFunction %void
1554 %main = OpFunction %void None %void_fn
1555 %entry = OpLabel
1556 OpReturn
1557 OpFunctionEnd
1558 )";
1559 
1560   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1561   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1562   EXPECT_THAT(
1563       getDiagnosticString(),
1564       HasSubstr(
1565           "The Target Type operand must be a floating-point scalar type"));
1566 }
1567 
TEST_F(ValidateMode,FPFastMathDefaultNotAFloatScalarType)1568 TEST_F(ValidateMode, FPFastMathDefaultNotAFloatScalarType) {
1569   const std::string spirv = R"(
1570 OpCapability Shader
1571 OpCapability FloatControls2
1572 OpExtension "SPV_KHR_float_controls2"
1573 OpMemoryModel Logical GLSL450
1574 OpEntryPoint GLCompute %main "main"
1575 OpExecutionMode %main LocalSize 1 1 1
1576 OpExecutionModeId %main FPFastMathDefault %float2 %int_0
1577 %void = OpTypeVoid
1578 %int = OpTypeInt 32 0
1579 %int_0 = OpConstant %int 0
1580 %float = OpTypeFloat 32
1581 %float2 = OpTypeVector %float 2
1582 %void_fn = OpTypeFunction %void
1583 %main = OpFunction %void None %void_fn
1584 %entry = OpLabel
1585 OpReturn
1586 OpFunctionEnd
1587 )";
1588 
1589   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1590   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1591   EXPECT_THAT(
1592       getDiagnosticString(),
1593       HasSubstr(
1594           "The Target Type operand must be a floating-point scalar type"));
1595 }
1596 
TEST_F(ValidateMode,FPFastMathDefaultSpecConstant)1597 TEST_F(ValidateMode, FPFastMathDefaultSpecConstant) {
1598   const std::string spirv = R"(
1599 OpCapability Shader
1600 OpCapability FloatControls2
1601 OpExtension "SPV_KHR_float_controls2"
1602 OpMemoryModel Logical GLSL450
1603 OpEntryPoint GLCompute %main "main"
1604 OpExecutionMode %main LocalSize 1 1 1
1605 OpExecutionModeId %main FPFastMathDefault %float %int_0
1606 %void = OpTypeVoid
1607 %int = OpTypeInt 32 0
1608 %int_0 = OpSpecConstant %int 0
1609 %float = OpTypeFloat 32
1610 %void_fn = OpTypeFunction %void
1611 %main = OpFunction %void None %void_fn
1612 %entry = OpLabel
1613 OpReturn
1614 OpFunctionEnd
1615 )";
1616 
1617   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1618   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1619   EXPECT_THAT(getDiagnosticString(),
1620               HasSubstr("The Fast Math Default operand must be a "
1621                         "non-specialization constant"));
1622 }
1623 
TEST_F(ValidateMode,FPFastMathDefaultInvalidMask)1624 TEST_F(ValidateMode, FPFastMathDefaultInvalidMask) {
1625   const std::string spirv = R"(
1626 OpCapability Shader
1627 OpCapability FloatControls2
1628 OpExtension "SPV_KHR_float_controls2"
1629 OpMemoryModel Logical GLSL450
1630 OpEntryPoint GLCompute %main "main"
1631 OpExecutionMode %main LocalSize 1 1 1
1632 OpExecutionModeId %main FPFastMathDefault %float %constant
1633 %void = OpTypeVoid
1634 %int = OpTypeInt 32 0
1635 %constant = OpConstant %int 524288
1636 %float = OpTypeFloat 32
1637 %void_fn = OpTypeFunction %void
1638 %main = OpFunction %void None %void_fn
1639 %entry = OpLabel
1640 OpReturn
1641 OpFunctionEnd
1642 )";
1643 
1644   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1645   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1646   EXPECT_THAT(
1647       getDiagnosticString(),
1648       HasSubstr("The Fast Math Default operand is an invalid bitmask value"));
1649 }
1650 
TEST_F(ValidateMode,FPFastMathDefaultContainsFast)1651 TEST_F(ValidateMode, FPFastMathDefaultContainsFast) {
1652   const std::string spirv = R"(
1653 OpCapability Shader
1654 OpCapability FloatControls2
1655 OpExtension "SPV_KHR_float_controls2"
1656 OpMemoryModel Logical GLSL450
1657 OpEntryPoint GLCompute %main "main"
1658 OpExecutionMode %main LocalSize 1 1 1
1659 OpExecutionModeId %main FPFastMathDefault %float %constant
1660 %void = OpTypeVoid
1661 %int = OpTypeInt 32 0
1662 %constant = OpConstant %int 16
1663 %float = OpTypeFloat 32
1664 %void_fn = OpTypeFunction %void
1665 %main = OpFunction %void None %void_fn
1666 %entry = OpLabel
1667 OpReturn
1668 OpFunctionEnd
1669 )";
1670 
1671   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1672   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1673   EXPECT_THAT(getDiagnosticString(),
1674               HasSubstr("The Fast Math Default operand must not include Fast"));
1675 }
1676 
TEST_F(ValidateMode,FPFastMathDefaultAllowTransformMissingAllowReassoc)1677 TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowReassoc) {
1678   const std::string spirv = R"(
1679 OpCapability Shader
1680 OpCapability FloatControls2
1681 OpExtension "SPV_KHR_float_controls2"
1682 OpMemoryModel Logical GLSL450
1683 OpEntryPoint GLCompute %main "main"
1684 OpExecutionMode %main LocalSize 1 1 1
1685 OpExecutionModeId %main FPFastMathDefault %float %constant
1686 %void = OpTypeVoid
1687 %int = OpTypeInt 32 0
1688 %constant = OpConstant %int 327680
1689 %float = OpTypeFloat 32
1690 %void_fn = OpTypeFunction %void
1691 %main = OpFunction %void None %void_fn
1692 %entry = OpLabel
1693 OpReturn
1694 OpFunctionEnd
1695 )";
1696 
1697   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1698   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1699   EXPECT_THAT(
1700       getDiagnosticString(),
1701       HasSubstr("The Fast Math Default operand must include AllowContract and "
1702                 "AllowReassoc when AllowTransform is specified"));
1703 }
1704 
TEST_F(ValidateMode,FPFastMathDefaultAllowTransformMissingAllowContract)1705 TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowContract) {
1706   const std::string spirv = R"(
1707 OpCapability Shader
1708 OpCapability FloatControls2
1709 OpExtension "SPV_KHR_float_controls2"
1710 OpMemoryModel Logical GLSL450
1711 OpEntryPoint GLCompute %main "main"
1712 OpExecutionMode %main LocalSize 1 1 1
1713 OpExecutionModeId %main FPFastMathDefault %float %constant
1714 %void = OpTypeVoid
1715 %int = OpTypeInt 32 0
1716 %constant = OpConstant %int 393216
1717 %float = OpTypeFloat 32
1718 %void_fn = OpTypeFunction %void
1719 %main = OpFunction %void None %void_fn
1720 %entry = OpLabel
1721 OpReturn
1722 OpFunctionEnd
1723 )";
1724 
1725   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1726   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1727   EXPECT_THAT(
1728       getDiagnosticString(),
1729       HasSubstr("The Fast Math Default operand must include AllowContract and "
1730                 "AllowReassoc when AllowTransform is specified"));
1731 }
1732 
TEST_F(ValidateMode,FPFastMathDefaultAllowTransformMissingContractAndReassoc)1733 TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingContractAndReassoc) {
1734   const std::string spirv = R"(
1735 OpCapability Shader
1736 OpCapability FloatControls2
1737 OpExtension "SPV_KHR_float_controls2"
1738 OpMemoryModel Logical GLSL450
1739 OpEntryPoint GLCompute %main "main"
1740 OpExecutionMode %main LocalSize 1 1 1
1741 OpExecutionModeId %main FPFastMathDefault %float %constant
1742 %void = OpTypeVoid
1743 %int = OpTypeInt 32 0
1744 %constant = OpConstant %int 262144
1745 %float = OpTypeFloat 32
1746 %void_fn = OpTypeFunction %void
1747 %main = OpFunction %void None %void_fn
1748 %entry = OpLabel
1749 OpReturn
1750 OpFunctionEnd
1751 )";
1752 
1753   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1754   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1755   EXPECT_THAT(
1756       getDiagnosticString(),
1757       HasSubstr("The Fast Math Default operand must include AllowContract and "
1758                 "AllowReassoc when AllowTransform is specified"));
1759 }
1760 
TEST_F(ValidateMode,FPFastMathDefaultSignedZeroInfNanPreserve)1761 TEST_F(ValidateMode, FPFastMathDefaultSignedZeroInfNanPreserve) {
1762   const std::string spirv = R"(
1763 OpCapability Shader
1764 OpCapability FloatControls2
1765 OpCapability SignedZeroInfNanPreserve
1766 OpExtension "SPV_KHR_float_controls2"
1767 OpExtension "SPV_KHR_float_controls"
1768 OpMemoryModel Logical GLSL450
1769 OpEntryPoint GLCompute %main "main"
1770 OpExecutionMode %main LocalSize 1 1 1
1771 OpExecutionModeId %main FPFastMathDefault %float %constant
1772 OpExecutionMode %main SignedZeroInfNanPreserve 32
1773 %void = OpTypeVoid
1774 %int = OpTypeInt 32 0
1775 %constant = OpConstant %int 0
1776 %float = OpTypeFloat 32
1777 %void_fn = OpTypeFunction %void
1778 %main = OpFunction %void None %void_fn
1779 %entry = OpLabel
1780 OpReturn
1781 OpFunctionEnd
1782 )";
1783 
1784   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1785   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1786             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1787   EXPECT_THAT(
1788       getDiagnosticString(),
1789       HasSubstr("FPFastMathDefault and SignedZeroInfNanPreserve execution "
1790                 "modes cannot be applied to the same entry point"));
1791 }
1792 
TEST_F(ValidateMode,FPFastMathDefaultConractionOff)1793 TEST_F(ValidateMode, FPFastMathDefaultConractionOff) {
1794   const std::string spirv = R"(
1795 OpCapability Kernel
1796 OpCapability Addresses
1797 OpCapability FloatControls2
1798 OpCapability SignedZeroInfNanPreserve
1799 OpExtension "SPV_KHR_float_controls2"
1800 OpExtension "SPV_KHR_float_controls"
1801 OpMemoryModel Physical64 OpenCL
1802 OpEntryPoint Kernel %main "main"
1803 OpExecutionModeId %main FPFastMathDefault %float %constant
1804 OpExecutionMode %main ContractionOff
1805 %void = OpTypeVoid
1806 %int = OpTypeInt 32 0
1807 %constant = OpConstant %int 0
1808 %float = OpTypeFloat 32
1809 %void_fn = OpTypeFunction %void
1810 %main = OpFunction %void None %void_fn
1811 %entry = OpLabel
1812 OpReturn
1813 OpFunctionEnd
1814 )";
1815 
1816   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1817   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1818             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1819   EXPECT_THAT(getDiagnosticString(),
1820               HasSubstr("FPFastMathDefault and ContractionOff execution modes "
1821                         "cannot be applied to the same entry point"));
1822 }
1823 
TEST_F(ValidateMode,FPFastMathDefaultNoContractionNotInCallTree)1824 TEST_F(ValidateMode, FPFastMathDefaultNoContractionNotInCallTree) {
1825   const std::string spirv = R"(
1826 OpCapability Shader
1827 OpCapability FloatControls2
1828 OpExtension "SPV_KHR_float_controls2"
1829 OpMemoryModel Logical GLSL450
1830 OpEntryPoint GLCompute %main "main"
1831 OpExecutionModeId %main FPFastMathDefault %float %constant
1832 OpExecutionMode %main LocalSize 1 1 1
1833 OpDecorate %add NoContraction
1834 %void = OpTypeVoid
1835 %int = OpTypeInt 32 0
1836 %constant = OpConstant %int 0
1837 %float = OpTypeFloat 32
1838 %zero = OpConstant %float 0
1839 %void_fn = OpTypeFunction %void
1840 %main = OpFunction %void None %void_fn
1841 %entry = OpLabel
1842 OpReturn
1843 OpFunctionEnd
1844 %func = OpFunction %void None %void_fn
1845 %func_entry = OpLabel
1846 %add = OpFAdd %float %zero %zero
1847 OpReturn
1848 OpFunctionEnd
1849 )";
1850 
1851   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1852   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1853 }
1854 
TEST_F(ValidateMode,FPFastMathDefaultNoContractionInCallTree)1855 TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree) {
1856   const std::string spirv = R"(
1857 OpCapability Shader
1858 OpCapability FloatControls2
1859 OpExtension "SPV_KHR_float_controls2"
1860 OpMemoryModel Logical GLSL450
1861 OpEntryPoint GLCompute %main "main"
1862 OpExecutionModeId %main FPFastMathDefault %float %constant
1863 OpExecutionMode %main LocalSize 1 1 1
1864 OpDecorate %add NoContraction
1865 %void = OpTypeVoid
1866 %int = OpTypeInt 32 0
1867 %constant = OpConstant %int 0
1868 %float = OpTypeFloat 32
1869 %zero = OpConstant %float 0
1870 %void_fn = OpTypeFunction %void
1871 %main = OpFunction %void None %void_fn
1872 %entry = OpLabel
1873 %call = OpFunctionCall %void %func
1874 OpReturn
1875 OpFunctionEnd
1876 %func = OpFunction %void None %void_fn
1877 %func_entry = OpLabel
1878 %add = OpFAdd %float %zero %zero
1879 OpReturn
1880 OpFunctionEnd
1881 )";
1882 
1883   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1884   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1885             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1886   EXPECT_THAT(getDiagnosticString(),
1887               HasSubstr("NoContraction cannot be used by an entry point with "
1888                         "the FPFastMathDefault execution mode"));
1889 }
1890 
TEST_F(ValidateMode,FPFastMathDefaultNoContractionInCallTree2)1891 TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree2) {
1892   const std::string spirv = R"(
1893 OpCapability Shader
1894 OpCapability Kernel
1895 OpCapability Addresses
1896 OpCapability FloatControls2
1897 OpExtension "SPV_KHR_float_controls2"
1898 OpMemoryModel Physical64 OpenCL
1899 OpEntryPoint Kernel %main "main"
1900 OpExecutionModeId %main FPFastMathDefault %float %constant
1901 OpDecorate %const NoContraction
1902 %void = OpTypeVoid
1903 %int = OpTypeInt 32 0
1904 %constant = OpConstant %int 0
1905 %float = OpTypeFloat 32
1906 %zero = OpConstant %float 0
1907 %const = OpSpecConstantOp %float FAdd %zero %zero
1908 %void_fn = OpTypeFunction %void
1909 %main = OpFunction %void None %void_fn
1910 %entry = OpLabel
1911 %call = OpFunctionCall %void %func
1912 OpReturn
1913 OpFunctionEnd
1914 %func = OpFunction %void None %void_fn
1915 %func_entry = OpLabel
1916 %add = OpFAdd %float %const %zero
1917 OpReturn
1918 OpFunctionEnd
1919 )";
1920 
1921   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1922   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1923             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1924   EXPECT_THAT(getDiagnosticString(),
1925               HasSubstr("NoContraction cannot be used by an entry point with "
1926                         "the FPFastMathDefault execution mode"));
1927 }
1928 
TEST_F(ValidateMode,FPFastMathDefaultFastMathFastNotInCallTree)1929 TEST_F(ValidateMode, FPFastMathDefaultFastMathFastNotInCallTree) {
1930   const std::string spirv = R"(
1931 OpCapability Shader
1932 OpCapability FloatControls2
1933 OpExtension "SPV_KHR_float_controls2"
1934 OpMemoryModel Logical GLSL450
1935 OpEntryPoint GLCompute %main "main"
1936 OpExecutionModeId %main FPFastMathDefault %float %constant
1937 OpExecutionMode %main LocalSize 1 1 1
1938 OpDecorate %add FPFastMathMode Fast
1939 %void = OpTypeVoid
1940 %int = OpTypeInt 32 0
1941 %constant = OpConstant %int 0
1942 %float = OpTypeFloat 32
1943 %zero = OpConstant %float 0
1944 %void_fn = OpTypeFunction %void
1945 %main = OpFunction %void None %void_fn
1946 %entry = OpLabel
1947 OpReturn
1948 OpFunctionEnd
1949 %func = OpFunction %void None %void_fn
1950 %func_entry = OpLabel
1951 %add = OpFAdd %float %zero %zero
1952 OpReturn
1953 OpFunctionEnd
1954 )";
1955 
1956   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1957   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1958 }
1959 
TEST_F(ValidateMode,FPFastMathDefaultFastMathFastInCallTree)1960 TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree) {
1961   const std::string spirv = R"(
1962 OpCapability Shader
1963 OpCapability FloatControls2
1964 OpExtension "SPV_KHR_float_controls2"
1965 OpMemoryModel Logical GLSL450
1966 OpEntryPoint GLCompute %main "main"
1967 OpExecutionModeId %main FPFastMathDefault %float %constant
1968 OpExecutionMode %main LocalSize 1 1 1
1969 OpDecorate %add FPFastMathMode Fast
1970 %void = OpTypeVoid
1971 %int = OpTypeInt 32 0
1972 %constant = OpConstant %int 0
1973 %float = OpTypeFloat 32
1974 %zero = OpConstant %float 0
1975 %void_fn = OpTypeFunction %void
1976 %main = OpFunction %void None %void_fn
1977 %entry = OpLabel
1978 %call = OpFunctionCall %void %func
1979 OpReturn
1980 OpFunctionEnd
1981 %func = OpFunction %void None %void_fn
1982 %func_entry = OpLabel
1983 %add = OpFAdd %float %zero %zero
1984 OpReturn
1985 OpFunctionEnd
1986 )";
1987 
1988   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1989   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
1990             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1991   EXPECT_THAT(getDiagnosticString(),
1992               HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
1993                         "with the FPFastMathDefault execution mode"));
1994 }
1995 
TEST_F(ValidateMode,FPFastMathDefaultFastMathFastInCallTree2)1996 TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree2) {
1997   const std::string spirv = R"(
1998 OpCapability Kernel
1999 OpCapability Addresses
2000 OpCapability FloatControls2
2001 OpExtension "SPV_KHR_float_controls2"
2002 OpMemoryModel Physical64 OpenCL
2003 OpEntryPoint Kernel %main "main"
2004 OpExecutionModeId %main FPFastMathDefault %float %constant
2005 OpDecorate %const FPFastMathMode Fast
2006 %void = OpTypeVoid
2007 %int = OpTypeInt 32 0
2008 %constant = OpConstant %int 0
2009 %float = OpTypeFloat 32
2010 %zero = OpConstant %float 0
2011 %const = OpSpecConstantOp %float FAdd %zero %zero
2012 %void_fn = OpTypeFunction %void
2013 %main = OpFunction %void None %void_fn
2014 %entry = OpLabel
2015 %call = OpFunctionCall %void %func
2016 OpReturn
2017 OpFunctionEnd
2018 %func = OpFunction %void None %void_fn
2019 %func_entry = OpLabel
2020 %add = OpFAdd %float %const %zero
2021 OpReturn
2022 OpFunctionEnd
2023 )";
2024 
2025   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
2026   EXPECT_EQ(SPV_ERROR_INVALID_DATA,
2027             ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2028   EXPECT_THAT(getDiagnosticString(),
2029               HasSubstr("FPFastMathMode Fast cannot be used by an entry point "
2030                         "with the FPFastMathDefault execution mode"));
2031 }
2032 
TEST_F(ValidateMode,FragmentShaderRequireFullQuadsKHR)2033 TEST_F(ValidateMode, FragmentShaderRequireFullQuadsKHR) {
2034   const std::string spirv = R"(
2035 OpCapability Shader
2036 OpCapability GroupNonUniform
2037 OpCapability GroupNonUniformVote
2038 OpCapability GroupNonUniformBallot
2039 OpCapability QuadControlKHR
2040 OpExtension "SPV_KHR_quad_control"
2041 %1 = OpExtInstImport "GLSL.std.450"
2042 OpMemoryModel Logical GLSL450
2043 OpEntryPoint GLCompute %4 "main"
2044 OpExecutionMode %4 OriginUpperLeft
2045 OpExecutionMode %4 RequireFullQuadsKHR
2046 OpDecorate %17 Location 0
2047 OpDecorate %31 BuiltIn HelperInvocation
2048 OpDecorate %40 Location 0
2049 OpDecorate %44 DescriptorSet 0
2050 OpDecorate %44 Binding 0
2051 %2 = OpTypeVoid
2052 %3 = OpTypeFunction %2
2053 %6 = OpTypeInt 32 0
2054 %7 = OpTypeVector %6 4
2055 %8 = OpTypePointer Function %7
2056 %10 = OpTypeBool
2057 %11 = OpConstantTrue %10
2058 %12 = OpConstant %6 7
2059 %14 = OpTypeFloat 32
2060 %15 = OpTypeVector %14 4
2061 %16 = OpTypePointer Output %15
2062 %17 = OpVariable %16 Output
2063 %18 = OpConstant %14 1
2064 %19 = OpConstant %14 0
2065 %20 = OpConstantComposite %15 %18 %19 %19 %18
2066 %23 = OpConstant %6 4
2067 %27 = OpConstant %6 1
2068 %28 = OpTypePointer Output %14
2069 %30 = OpTypePointer Input %10
2070 %31 = OpVariable %30 Input
2071 %36 = OpConstant %6 2
2072 %38 = OpTypeVector %14 2
2073 %39 = OpTypePointer Input %38
2074 %40 = OpVariable %39 Input
2075 %41 = OpTypeImage %14 2D 0 0 0 1 Unknown
2076 %42 = OpTypeSampledImage %41
2077 %43 = OpTypePointer UniformConstant %42
2078 %44 = OpVariable %43 UniformConstant
2079 %4 = OpFunction %2 None %3
2080 %5 = OpLabel
2081 %9 = OpVariable %8 Function
2082 %13 = OpGroupNonUniformBallot %7 %12 %11
2083 OpStore %9 %13
2084 OpStore %17 %20
2085 %21 = OpLoad %7 %9
2086 %22 = OpGroupNonUniformBallotBitCount %6 %12 Reduce %21
2087 %24 = OpIEqual %10 %22 %23
2088 OpSelectionMerge %26 None
2089 OpBranchConditional %24 %25 %26
2090 %25 = OpLabel
2091 %29 = OpAccessChain %28 %17 %27
2092 OpStore %29 %18
2093 OpBranch %26
2094 %26 = OpLabel
2095 %32 = OpLoad %10 %31
2096 %33 = OpGroupNonUniformAny %10 %12 %32
2097 OpSelectionMerge %35 None
2098 OpBranchConditional %33 %34 %35
2099 %34 = OpLabel
2100 %37 = OpAccessChain %28 %17 %36
2101 OpStore %37 %18
2102 OpBranch %35
2103 %35 = OpLabel
2104 OpReturn
2105 OpFunctionEnd
2106 )";
2107 
2108   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
2109   EXPECT_THAT(SPV_ERROR_INVALID_DATA,
2110               ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2111   EXPECT_THAT(
2112       getDiagnosticString(),
2113       HasSubstr(
2114           "Execution mode can only be used with the Fragment execution model"));
2115 }
2116 
TEST_F(ValidateMode,FragmentShaderQuadDerivativesKHR)2117 TEST_F(ValidateMode, FragmentShaderQuadDerivativesKHR) {
2118   const std::string spirv = R"(
2119 OpCapability Shader
2120 OpCapability GroupNonUniform
2121 OpCapability GroupNonUniformVote
2122 OpCapability QuadControlKHR
2123 OpExtension "SPV_KHR_quad_control"
2124 %1 = OpExtInstImport "GLSL.std.450"
2125 OpMemoryModel Logical GLSL450
2126 OpEntryPoint GLCompute %4 "main"
2127 OpExecutionMode %4 OriginUpperLeft
2128 OpExecutionMode %4 QuadDerivativesKHR
2129 OpDecorate %12 BuiltIn FragCoord
2130 OpDecorate %41 Location 0
2131 OpDecorate %45 DescriptorSet 0
2132 OpDecorate %45 Binding 0
2133 OpDecorate %49 Location 0
2134 %2 = OpTypeVoid
2135 %3 = OpTypeFunction %2
2136 %6 = OpTypeBool
2137 %7 = OpTypePointer Function %6
2138 %9 = OpTypeFloat 32
2139 %10 = OpTypeVector %9 4
2140 %11 = OpTypePointer Input %10
2141 %12 = OpVariable %11 Input
2142 %13 = OpTypeInt 32 0
2143 %14 = OpConstant %13 1
2144 %15 = OpTypePointer Input %9
2145 %18 = OpConstant %9 8.5
2146 %21 = OpConstant %9 0.100000001
2147 %25 = OpConstant %13 0
2148 %28 = OpConstant %9 3.5
2149 %30 = OpConstant %9 6
2150 %36 = OpConstant %13 7
2151 %40 = OpTypePointer Output %10
2152 %41 = OpVariable %40 Output
2153 %42 = OpTypeImage %9 2D 0 0 0 1 Unknown
2154 %43 = OpTypeSampledImage %42
2155 %44 = OpTypePointer UniformConstant %43
2156 %45 = OpVariable %44 UniformConstant
2157 %47 = OpTypeVector %9 2
2158 %48 = OpTypePointer Input %47
2159 %49 = OpVariable %48 Input
2160 %53 = OpConstant %9 0.899999976
2161 %54 = OpConstant %9 0.200000003
2162 %55 = OpConstant %9 1
2163 %56 = OpConstantComposite %10 %53 %54 %54 %55
2164 %4 = OpFunction %2 None %3
2165 %5 = OpLabel
2166 %8 = OpVariable %7 Function
2167 %16 = OpAccessChain %15 %12 %14
2168 %17 = OpLoad %9 %16
2169 %19 = OpFSub %9 %17 %18
2170 %20 = OpExtInst %9 %1 FAbs %19
2171 %22 = OpFOrdLessThan %6 %20 %21
2172 OpSelectionMerge %24 None
2173 OpBranchConditional %22 %23 %24
2174 %23 = OpLabel
2175 %26 = OpAccessChain %15 %12 %25
2176 %27 = OpLoad %9 %26
2177 %29 = OpFSub %9 %27 %28
2178 %31 = OpFMod %9 %29 %30
2179 %33 = OpFOrdLessThan %6 %31 %21
2180 OpBranch %24
2181 %24 = OpLabel
2182 %34 = OpPhi %6 %22 %5 %33 %23
2183 OpStore %8 %34
2184 %35 = OpLoad %6 %8
2185 %37 = OpGroupNonUniformAny %6 %36 %35
2186 OpSelectionMerge %39 None
2187 OpBranchConditional %37 %38 %52
2188 %38 = OpLabel
2189 %46 = OpLoad %43 %45
2190 %50 = OpLoad %47 %49
2191 %51 = OpImageSampleImplicitLod %10 %46 %50
2192 OpStore %41 %51
2193 OpBranch %39
2194 %52 = OpLabel
2195 OpStore %41 %56
2196 OpBranch %39
2197 %39 = OpLabel
2198 OpReturn
2199 OpFunctionEnd
2200 )";
2201 
2202   CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
2203   EXPECT_THAT(SPV_ERROR_INVALID_DATA,
2204               ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
2205   EXPECT_THAT(
2206       getDiagnosticString(),
2207       HasSubstr(
2208           "Execution mode can only be used with the Fragment execution model"));
2209 }
2210 
2211 }  // namespace
2212 }  // namespace val
2213 }  // namespace spvtools
2214