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 <algorithm>
16
17 #include "source/opcode.h"
18 #include "source/spirv_target_env.h"
19 #include "source/val/instruction.h"
20 #include "source/val/validate.h"
21 #include "source/val/validation_state.h"
22
23 namespace spvtools {
24 namespace val {
25 namespace {
26
ValidateEntryPoint(ValidationState_t & _,const Instruction * inst)27 spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
28 const auto entry_point_id = inst->GetOperandAs<uint32_t>(1);
29 auto entry_point = _.FindDef(entry_point_id);
30 if (!entry_point || SpvOpFunction != entry_point->opcode()) {
31 return _.diag(SPV_ERROR_INVALID_ID, inst)
32 << "OpEntryPoint Entry Point <id> " << _.getIdName(entry_point_id)
33 << " is not a function.";
34 }
35
36 // Only check the shader execution models
37 const SpvExecutionModel execution_model =
38 inst->GetOperandAs<SpvExecutionModel>(0);
39 if (execution_model != SpvExecutionModelKernel) {
40 const auto entry_point_type_id = entry_point->GetOperandAs<uint32_t>(3);
41 const auto entry_point_type = _.FindDef(entry_point_type_id);
42 if (!entry_point_type || 3 != entry_point_type->words().size()) {
43 return _.diag(SPV_ERROR_INVALID_ID, inst)
44 << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> "
45 << _.getIdName(entry_point_id)
46 << "s function parameter count is not zero.";
47 }
48 }
49
50 auto return_type = _.FindDef(entry_point->type_id());
51 if (!return_type || SpvOpTypeVoid != return_type->opcode()) {
52 return _.diag(SPV_ERROR_INVALID_ID, inst)
53 << _.VkErrorID(4633) << "OpEntryPoint Entry Point <id> "
54 << _.getIdName(entry_point_id)
55 << "s function return type is not void.";
56 }
57
58 const auto* execution_modes = _.GetExecutionModes(entry_point_id);
59 if (_.HasCapability(SpvCapabilityShader)) {
60 switch (execution_model) {
61 case SpvExecutionModelFragment:
62 if (execution_modes &&
63 execution_modes->count(SpvExecutionModeOriginUpperLeft) &&
64 execution_modes->count(SpvExecutionModeOriginLowerLeft)) {
65 return _.diag(SPV_ERROR_INVALID_DATA, inst)
66 << "Fragment execution model entry points can only specify "
67 "one of OriginUpperLeft or OriginLowerLeft execution "
68 "modes.";
69 }
70 if (!execution_modes ||
71 (!execution_modes->count(SpvExecutionModeOriginUpperLeft) &&
72 !execution_modes->count(SpvExecutionModeOriginLowerLeft))) {
73 return _.diag(SPV_ERROR_INVALID_DATA, inst)
74 << "Fragment execution model entry points require either an "
75 "OriginUpperLeft or OriginLowerLeft execution mode.";
76 }
77 if (execution_modes &&
78 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
79 [](const SpvExecutionMode& mode) {
80 switch (mode) {
81 case SpvExecutionModeDepthGreater:
82 case SpvExecutionModeDepthLess:
83 case SpvExecutionModeDepthUnchanged:
84 return true;
85 default:
86 return false;
87 }
88 })) {
89 return _.diag(SPV_ERROR_INVALID_DATA, inst)
90 << "Fragment execution model entry points can specify at most "
91 "one of DepthGreater, DepthLess or DepthUnchanged "
92 "execution modes.";
93 }
94 if (execution_modes &&
95 1 < std::count_if(
96 execution_modes->begin(), execution_modes->end(),
97 [](const SpvExecutionMode& mode) {
98 switch (mode) {
99 case SpvExecutionModePixelInterlockOrderedEXT:
100 case SpvExecutionModePixelInterlockUnorderedEXT:
101 case SpvExecutionModeSampleInterlockOrderedEXT:
102 case SpvExecutionModeSampleInterlockUnorderedEXT:
103 case SpvExecutionModeShadingRateInterlockOrderedEXT:
104 case SpvExecutionModeShadingRateInterlockUnorderedEXT:
105 return true;
106 default:
107 return false;
108 }
109 })) {
110 return _.diag(SPV_ERROR_INVALID_DATA, inst)
111 << "Fragment execution model entry points can specify at most "
112 "one fragment shader interlock execution mode.";
113 }
114 if (execution_modes &&
115 1 < std::count_if(
116 execution_modes->begin(), execution_modes->end(),
117 [](const SpvExecutionMode& mode) {
118 switch (mode) {
119 case SpvExecutionModeStencilRefUnchangedFrontAMD:
120 case SpvExecutionModeStencilRefLessFrontAMD:
121 case SpvExecutionModeStencilRefGreaterFrontAMD:
122 return true;
123 default:
124 return false;
125 }
126 })) {
127 return _.diag(SPV_ERROR_INVALID_DATA, inst)
128 << "Fragment execution model entry points can specify at most "
129 "one of StencilRefUnchangedFrontAMD, "
130 "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
131 "execution modes.";
132 }
133 if (execution_modes &&
134 1 < std::count_if(
135 execution_modes->begin(), execution_modes->end(),
136 [](const SpvExecutionMode& mode) {
137 switch (mode) {
138 case SpvExecutionModeStencilRefUnchangedBackAMD:
139 case SpvExecutionModeStencilRefLessBackAMD:
140 case SpvExecutionModeStencilRefGreaterBackAMD:
141 return true;
142 default:
143 return false;
144 }
145 })) {
146 return _.diag(SPV_ERROR_INVALID_DATA, inst)
147 << "Fragment execution model entry points can specify at most "
148 "one of StencilRefUnchangedBackAMD, "
149 "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
150 "execution modes.";
151 }
152 break;
153 case SpvExecutionModelTessellationControl:
154 case SpvExecutionModelTessellationEvaluation:
155 if (execution_modes &&
156 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
157 [](const SpvExecutionMode& mode) {
158 switch (mode) {
159 case SpvExecutionModeSpacingEqual:
160 case SpvExecutionModeSpacingFractionalEven:
161 case SpvExecutionModeSpacingFractionalOdd:
162 return true;
163 default:
164 return false;
165 }
166 })) {
167 return _.diag(SPV_ERROR_INVALID_DATA, inst)
168 << "Tessellation execution model entry points can specify at "
169 "most one of SpacingEqual, SpacingFractionalOdd or "
170 "SpacingFractionalEven execution modes.";
171 }
172 if (execution_modes &&
173 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
174 [](const SpvExecutionMode& mode) {
175 switch (mode) {
176 case SpvExecutionModeTriangles:
177 case SpvExecutionModeQuads:
178 case SpvExecutionModeIsolines:
179 return true;
180 default:
181 return false;
182 }
183 })) {
184 return _.diag(SPV_ERROR_INVALID_DATA, inst)
185 << "Tessellation execution model entry points can specify at "
186 "most one of Triangles, Quads or Isolines execution modes.";
187 }
188 if (execution_modes &&
189 1 < std::count_if(execution_modes->begin(), execution_modes->end(),
190 [](const SpvExecutionMode& mode) {
191 switch (mode) {
192 case SpvExecutionModeVertexOrderCw:
193 case SpvExecutionModeVertexOrderCcw:
194 return true;
195 default:
196 return false;
197 }
198 })) {
199 return _.diag(SPV_ERROR_INVALID_DATA, inst)
200 << "Tessellation execution model entry points can specify at "
201 "most one of VertexOrderCw or VertexOrderCcw execution "
202 "modes.";
203 }
204 break;
205 case SpvExecutionModelGeometry:
206 if (!execution_modes ||
207 1 != std::count_if(execution_modes->begin(), execution_modes->end(),
208 [](const SpvExecutionMode& mode) {
209 switch (mode) {
210 case SpvExecutionModeInputPoints:
211 case SpvExecutionModeInputLines:
212 case SpvExecutionModeInputLinesAdjacency:
213 case SpvExecutionModeTriangles:
214 case SpvExecutionModeInputTrianglesAdjacency:
215 return true;
216 default:
217 return false;
218 }
219 })) {
220 return _.diag(SPV_ERROR_INVALID_DATA, inst)
221 << "Geometry execution model entry points must specify "
222 "exactly one of InputPoints, InputLines, "
223 "InputLinesAdjacency, Triangles or InputTrianglesAdjacency "
224 "execution modes.";
225 }
226 if (!execution_modes ||
227 1 != std::count_if(execution_modes->begin(), execution_modes->end(),
228 [](const SpvExecutionMode& mode) {
229 switch (mode) {
230 case SpvExecutionModeOutputPoints:
231 case SpvExecutionModeOutputLineStrip:
232 case SpvExecutionModeOutputTriangleStrip:
233 return true;
234 default:
235 return false;
236 }
237 })) {
238 return _.diag(SPV_ERROR_INVALID_DATA, inst)
239 << "Geometry execution model entry points must specify "
240 "exactly one of OutputPoints, OutputLineStrip or "
241 "OutputTriangleStrip execution modes.";
242 }
243 break;
244 case SpvExecutionModelMeshEXT:
245 if (!execution_modes ||
246 1 != std::count_if(execution_modes->begin(), execution_modes->end(),
247 [](const SpvExecutionMode& mode) {
248 switch (mode) {
249 case SpvExecutionModeOutputPoints:
250 case SpvExecutionModeOutputLinesEXT:
251 case SpvExecutionModeOutputTrianglesEXT:
252 return true;
253 default:
254 return false;
255 }
256 })) {
257 return _.diag(SPV_ERROR_INVALID_DATA, inst)
258 << "MeshEXT execution model entry points must specify exactly "
259 "one of OutputPoints, OutputLinesEXT, or "
260 "OutputTrianglesEXT Execution Modes.";
261 } else if (2 != std::count_if(
262 execution_modes->begin(), execution_modes->end(),
263 [](const SpvExecutionMode& mode) {
264 switch (mode) {
265 case SpvExecutionModeOutputPrimitivesEXT:
266 case SpvExecutionModeOutputVertices:
267 return true;
268 default:
269 return false;
270 }
271 })) {
272 return _.diag(SPV_ERROR_INVALID_DATA, inst)
273 << "MeshEXT execution model entry points must specify both "
274 "OutputPrimitivesEXT and OutputVertices Execution Modes.";
275 }
276 break;
277 default:
278 break;
279 }
280 }
281
282 if (spvIsVulkanEnv(_.context()->target_env)) {
283 switch (execution_model) {
284 case SpvExecutionModelGLCompute:
285 if (!execution_modes ||
286 !execution_modes->count(SpvExecutionModeLocalSize)) {
287 bool ok = false;
288 for (auto& i : _.ordered_instructions()) {
289 if (i.opcode() == SpvOpDecorate) {
290 if (i.operands().size() > 2) {
291 if (i.GetOperandAs<SpvDecoration>(1) == SpvDecorationBuiltIn &&
292 i.GetOperandAs<SpvBuiltIn>(2) == SpvBuiltInWorkgroupSize) {
293 ok = true;
294 break;
295 }
296 }
297 }
298 if (i.opcode() == SpvOpExecutionModeId) {
299 const auto mode = i.GetOperandAs<SpvExecutionMode>(1);
300 if (mode == SpvExecutionModeLocalSizeId) {
301 ok = true;
302 break;
303 }
304 }
305 }
306 if (!ok) {
307 return _.diag(SPV_ERROR_INVALID_DATA, inst)
308 << _.VkErrorID(6426)
309 << "In the Vulkan environment, GLCompute execution model "
310 "entry points require either the LocalSize or "
311 "LocalSizeId execution mode or an object decorated with "
312 "WorkgroupSize must be specified.";
313 }
314 }
315 break;
316 default:
317 break;
318 }
319 }
320
321 return SPV_SUCCESS;
322 }
323
ValidateExecutionMode(ValidationState_t & _,const Instruction * inst)324 spv_result_t ValidateExecutionMode(ValidationState_t& _,
325 const Instruction* inst) {
326 const auto entry_point_id = inst->GetOperandAs<uint32_t>(0);
327 const auto found = std::find(_.entry_points().cbegin(),
328 _.entry_points().cend(), entry_point_id);
329 if (found == _.entry_points().cend()) {
330 return _.diag(SPV_ERROR_INVALID_ID, inst)
331 << "OpExecutionMode Entry Point <id> " << _.getIdName(entry_point_id)
332 << " is not the Entry Point "
333 "operand of an OpEntryPoint.";
334 }
335
336 const auto mode = inst->GetOperandAs<SpvExecutionMode>(1);
337 if (inst->opcode() == SpvOpExecutionModeId) {
338 size_t operand_count = inst->operands().size();
339 for (size_t i = 2; i < operand_count; ++i) {
340 const auto operand_id = inst->GetOperandAs<uint32_t>(2);
341 const auto* operand_inst = _.FindDef(operand_id);
342 if (mode == SpvExecutionModeSubgroupsPerWorkgroupId ||
343 mode == SpvExecutionModeLocalSizeHintId ||
344 mode == SpvExecutionModeLocalSizeId) {
345 if (!spvOpcodeIsConstant(operand_inst->opcode())) {
346 return _.diag(SPV_ERROR_INVALID_ID, inst)
347 << "For OpExecutionModeId all Extra Operand ids must be "
348 "constant "
349 "instructions.";
350 }
351 } else {
352 return _.diag(SPV_ERROR_INVALID_ID, inst)
353 << "OpExecutionModeId is only valid when the Mode operand is an "
354 "execution mode that takes Extra Operands that are id "
355 "operands.";
356 }
357 }
358 } else if (mode == SpvExecutionModeSubgroupsPerWorkgroupId ||
359 mode == SpvExecutionModeLocalSizeHintId ||
360 mode == SpvExecutionModeLocalSizeId) {
361 return _.diag(SPV_ERROR_INVALID_DATA, inst)
362 << "OpExecutionMode is only valid when the Mode operand is an "
363 "execution mode that takes no Extra Operands, or takes Extra "
364 "Operands that are not id operands.";
365 }
366
367 const auto* models = _.GetExecutionModels(entry_point_id);
368 switch (mode) {
369 case SpvExecutionModeInvocations:
370 case SpvExecutionModeInputPoints:
371 case SpvExecutionModeInputLines:
372 case SpvExecutionModeInputLinesAdjacency:
373 case SpvExecutionModeInputTrianglesAdjacency:
374 case SpvExecutionModeOutputLineStrip:
375 case SpvExecutionModeOutputTriangleStrip:
376 if (!std::all_of(models->begin(), models->end(),
377 [](const SpvExecutionModel& model) {
378 return model == SpvExecutionModelGeometry;
379 })) {
380 return _.diag(SPV_ERROR_INVALID_DATA, inst)
381 << "Execution mode can only be used with the Geometry execution "
382 "model.";
383 }
384 break;
385 case SpvExecutionModeOutputPoints:
386 if (!std::all_of(models->begin(), models->end(),
387 [&_](const SpvExecutionModel& model) {
388 switch (model) {
389 case SpvExecutionModelGeometry:
390 return true;
391 case SpvExecutionModelMeshNV:
392 return _.HasCapability(SpvCapabilityMeshShadingNV);
393 case SpvExecutionModelMeshEXT:
394 return _.HasCapability(
395 SpvCapabilityMeshShadingEXT);
396 default:
397 return false;
398 }
399 })) {
400 if (_.HasCapability(SpvCapabilityMeshShadingNV) ||
401 _.HasCapability(SpvCapabilityMeshShadingEXT)) {
402 return _.diag(SPV_ERROR_INVALID_DATA, inst)
403 << "Execution mode can only be used with the Geometry "
404 "MeshNV or MeshEXT execution model.";
405 } else {
406 return _.diag(SPV_ERROR_INVALID_DATA, inst)
407 << "Execution mode can only be used with the Geometry "
408 "execution "
409 "model.";
410 }
411 }
412 break;
413 case SpvExecutionModeSpacingEqual:
414 case SpvExecutionModeSpacingFractionalEven:
415 case SpvExecutionModeSpacingFractionalOdd:
416 case SpvExecutionModeVertexOrderCw:
417 case SpvExecutionModeVertexOrderCcw:
418 case SpvExecutionModePointMode:
419 case SpvExecutionModeQuads:
420 case SpvExecutionModeIsolines:
421 if (!std::all_of(
422 models->begin(), models->end(),
423 [](const SpvExecutionModel& model) {
424 return (model == SpvExecutionModelTessellationControl) ||
425 (model == SpvExecutionModelTessellationEvaluation);
426 })) {
427 return _.diag(SPV_ERROR_INVALID_DATA, inst)
428 << "Execution mode can only be used with a tessellation "
429 "execution model.";
430 }
431 break;
432 case SpvExecutionModeTriangles:
433 if (!std::all_of(models->begin(), models->end(),
434 [](const SpvExecutionModel& model) {
435 switch (model) {
436 case SpvExecutionModelGeometry:
437 case SpvExecutionModelTessellationControl:
438 case SpvExecutionModelTessellationEvaluation:
439 return true;
440 default:
441 return false;
442 }
443 })) {
444 return _.diag(SPV_ERROR_INVALID_DATA, inst)
445 << "Execution mode can only be used with a Geometry or "
446 "tessellation execution model.";
447 }
448 break;
449 case SpvExecutionModeOutputVertices:
450 if (!std::all_of(models->begin(), models->end(),
451 [&_](const SpvExecutionModel& model) {
452 switch (model) {
453 case SpvExecutionModelGeometry:
454 case SpvExecutionModelTessellationControl:
455 case SpvExecutionModelTessellationEvaluation:
456 return true;
457 case SpvExecutionModelMeshNV:
458 return _.HasCapability(SpvCapabilityMeshShadingNV);
459 case SpvExecutionModelMeshEXT:
460 return _.HasCapability(
461 SpvCapabilityMeshShadingEXT);
462 default:
463 return false;
464 }
465 })) {
466 if (_.HasCapability(SpvCapabilityMeshShadingNV) ||
467 _.HasCapability(SpvCapabilityMeshShadingEXT)) {
468 return _.diag(SPV_ERROR_INVALID_DATA, inst)
469 << "Execution mode can only be used with a Geometry, "
470 "tessellation, MeshNV or MeshEXT execution model.";
471 } else {
472 return _.diag(SPV_ERROR_INVALID_DATA, inst)
473 << "Execution mode can only be used with a Geometry or "
474 "tessellation execution model.";
475 }
476 }
477 break;
478 case SpvExecutionModeOutputLinesEXT:
479 case SpvExecutionModeOutputTrianglesEXT:
480 case SpvExecutionModeOutputPrimitivesEXT:
481 if (!std::all_of(models->begin(), models->end(),
482 [](const SpvExecutionModel& model) {
483 return (model == SpvExecutionModelMeshEXT ||
484 model == SpvExecutionModelMeshNV);
485 })) {
486 return _.diag(SPV_ERROR_INVALID_DATA, inst)
487 << "Execution mode can only be used with the MeshEXT or MeshNV "
488 "execution "
489 "model.";
490 }
491 break;
492 case SpvExecutionModePixelCenterInteger:
493 case SpvExecutionModeOriginUpperLeft:
494 case SpvExecutionModeOriginLowerLeft:
495 case SpvExecutionModeEarlyFragmentTests:
496 case SpvExecutionModeDepthReplacing:
497 case SpvExecutionModeDepthGreater:
498 case SpvExecutionModeDepthLess:
499 case SpvExecutionModeDepthUnchanged:
500 case SpvExecutionModePixelInterlockOrderedEXT:
501 case SpvExecutionModePixelInterlockUnorderedEXT:
502 case SpvExecutionModeSampleInterlockOrderedEXT:
503 case SpvExecutionModeSampleInterlockUnorderedEXT:
504 case SpvExecutionModeShadingRateInterlockOrderedEXT:
505 case SpvExecutionModeShadingRateInterlockUnorderedEXT:
506 case SpvExecutionModeEarlyAndLateFragmentTestsAMD:
507 case SpvExecutionModeStencilRefUnchangedFrontAMD:
508 case SpvExecutionModeStencilRefGreaterFrontAMD:
509 case SpvExecutionModeStencilRefLessFrontAMD:
510 case SpvExecutionModeStencilRefUnchangedBackAMD:
511 case SpvExecutionModeStencilRefGreaterBackAMD:
512 case SpvExecutionModeStencilRefLessBackAMD:
513 if (!std::all_of(models->begin(), models->end(),
514 [](const SpvExecutionModel& model) {
515 return model == SpvExecutionModelFragment;
516 })) {
517 return _.diag(SPV_ERROR_INVALID_DATA, inst)
518 << "Execution mode can only be used with the Fragment execution "
519 "model.";
520 }
521 break;
522 case SpvExecutionModeLocalSizeHint:
523 case SpvExecutionModeVecTypeHint:
524 case SpvExecutionModeContractionOff:
525 case SpvExecutionModeLocalSizeHintId:
526 if (!std::all_of(models->begin(), models->end(),
527 [](const SpvExecutionModel& model) {
528 return model == SpvExecutionModelKernel;
529 })) {
530 return _.diag(SPV_ERROR_INVALID_DATA, inst)
531 << "Execution mode can only be used with the Kernel execution "
532 "model.";
533 }
534 break;
535 case SpvExecutionModeLocalSize:
536 case SpvExecutionModeLocalSizeId:
537 if (mode == SpvExecutionModeLocalSizeId && !_.IsLocalSizeIdAllowed())
538 return _.diag(SPV_ERROR_INVALID_DATA, inst)
539 << "LocalSizeId mode is not allowed by the current environment.";
540
541 if (!std::all_of(models->begin(), models->end(),
542 [&_](const SpvExecutionModel& model) {
543 switch (model) {
544 case SpvExecutionModelKernel:
545 case SpvExecutionModelGLCompute:
546 return true;
547 case SpvExecutionModelTaskNV:
548 case SpvExecutionModelMeshNV:
549 return _.HasCapability(SpvCapabilityMeshShadingNV);
550 case SpvExecutionModelTaskEXT:
551 case SpvExecutionModelMeshEXT:
552 return _.HasCapability(
553 SpvCapabilityMeshShadingEXT);
554 default:
555 return false;
556 }
557 })) {
558 if (_.HasCapability(SpvCapabilityMeshShadingNV) ||
559 _.HasCapability(SpvCapabilityMeshShadingEXT)) {
560 return _.diag(SPV_ERROR_INVALID_DATA, inst)
561 << "Execution mode can only be used with a Kernel, GLCompute, "
562 "MeshNV, MeshEXT, TaskNV or TaskEXT execution model.";
563 } else {
564 return _.diag(SPV_ERROR_INVALID_DATA, inst)
565 << "Execution mode can only be used with a Kernel or "
566 "GLCompute "
567 "execution model.";
568 }
569 }
570 default:
571 break;
572 }
573
574 if (spvIsVulkanEnv(_.context()->target_env)) {
575 if (mode == SpvExecutionModeOriginLowerLeft) {
576 return _.diag(SPV_ERROR_INVALID_DATA, inst)
577 << _.VkErrorID(4653)
578 << "In the Vulkan environment, the OriginLowerLeft execution mode "
579 "must not be used.";
580 }
581 if (mode == SpvExecutionModePixelCenterInteger) {
582 return _.diag(SPV_ERROR_INVALID_DATA, inst)
583 << _.VkErrorID(4654)
584 << "In the Vulkan environment, the PixelCenterInteger execution "
585 "mode must not be used.";
586 }
587 }
588
589 return SPV_SUCCESS;
590 }
591
ValidateMemoryModel(ValidationState_t & _,const Instruction * inst)592 spv_result_t ValidateMemoryModel(ValidationState_t& _,
593 const Instruction* inst) {
594 // Already produced an error if multiple memory model instructions are
595 // present.
596 if (_.memory_model() != SpvMemoryModelVulkanKHR &&
597 _.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) {
598 return _.diag(SPV_ERROR_INVALID_DATA, inst)
599 << "VulkanMemoryModelKHR capability must only be specified if "
600 "the VulkanKHR memory model is used.";
601 }
602
603 if (spvIsOpenCLEnv(_.context()->target_env)) {
604 if ((_.addressing_model() != SpvAddressingModelPhysical32) &&
605 (_.addressing_model() != SpvAddressingModelPhysical64)) {
606 return _.diag(SPV_ERROR_INVALID_DATA, inst)
607 << "Addressing model must be Physical32 or Physical64 "
608 << "in the OpenCL environment.";
609 }
610 if (_.memory_model() != SpvMemoryModelOpenCL) {
611 return _.diag(SPV_ERROR_INVALID_DATA, inst)
612 << "Memory model must be OpenCL in the OpenCL environment.";
613 }
614 }
615
616 if (spvIsVulkanEnv(_.context()->target_env)) {
617 if ((_.addressing_model() != SpvAddressingModelLogical) &&
618 (_.addressing_model() != SpvAddressingModelPhysicalStorageBuffer64)) {
619 return _.diag(SPV_ERROR_INVALID_DATA, inst)
620 << _.VkErrorID(4635)
621 << "Addressing model must be Logical or PhysicalStorageBuffer64 "
622 << "in the Vulkan environment.";
623 }
624 }
625 return SPV_SUCCESS;
626 }
627
628 } // namespace
629
ModeSettingPass(ValidationState_t & _,const Instruction * inst)630 spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
631 switch (inst->opcode()) {
632 case SpvOpEntryPoint:
633 if (auto error = ValidateEntryPoint(_, inst)) return error;
634 break;
635 case SpvOpExecutionMode:
636 case SpvOpExecutionModeId:
637 if (auto error = ValidateExecutionMode(_, inst)) return error;
638 break;
639 case SpvOpMemoryModel:
640 if (auto error = ValidateMemoryModel(_, inst)) return error;
641 break;
642 default:
643 break;
644 }
645 return SPV_SUCCESS;
646 }
647
648 } // namespace val
649 } // namespace spvtools
650