• 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 <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