• 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 || spv::Op::OpFunction != 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 spv::ExecutionModel execution_model =
38       inst->GetOperandAs<spv::ExecutionModel>(0);
39   if (execution_model != spv::ExecutionModel::Kernel) {
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 || spv::Op::OpTypeVoid != 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(spv::Capability::Shader)) {
60     switch (execution_model) {
61       case spv::ExecutionModel::Fragment:
62         if (execution_modes &&
63             execution_modes->count(spv::ExecutionMode::OriginUpperLeft) &&
64             execution_modes->count(spv::ExecutionMode::OriginLowerLeft)) {
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(spv::ExecutionMode::OriginUpperLeft) &&
72              !execution_modes->count(spv::ExecutionMode::OriginLowerLeft))) {
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 spv::ExecutionMode& mode) {
80                                 switch (mode) {
81                                   case spv::ExecutionMode::DepthGreater:
82                                   case spv::ExecutionMode::DepthLess:
83                                   case spv::ExecutionMode::DepthUnchanged:
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 spv::ExecutionMode& mode) {
98                       switch (mode) {
99                         case spv::ExecutionMode::PixelInterlockOrderedEXT:
100                         case spv::ExecutionMode::PixelInterlockUnorderedEXT:
101                         case spv::ExecutionMode::SampleInterlockOrderedEXT:
102                         case spv::ExecutionMode::SampleInterlockUnorderedEXT:
103                         case spv::ExecutionMode::ShadingRateInterlockOrderedEXT:
104                         case spv::ExecutionMode::
105                             ShadingRateInterlockUnorderedEXT:
106                           return true;
107                         default:
108                           return false;
109                       }
110                     })) {
111           return _.diag(SPV_ERROR_INVALID_DATA, inst)
112                  << "Fragment execution model entry points can specify at most "
113                     "one fragment shader interlock execution mode.";
114         }
115         if (execution_modes &&
116             1 < std::count_if(
117                     execution_modes->begin(), execution_modes->end(),
118                     [](const spv::ExecutionMode& mode) {
119                       switch (mode) {
120                         case spv::ExecutionMode::StencilRefUnchangedFrontAMD:
121                         case spv::ExecutionMode::StencilRefLessFrontAMD:
122                         case spv::ExecutionMode::StencilRefGreaterFrontAMD:
123                           return true;
124                         default:
125                           return false;
126                       }
127                     })) {
128           return _.diag(SPV_ERROR_INVALID_DATA, inst)
129                  << "Fragment execution model entry points can specify at most "
130                     "one of StencilRefUnchangedFrontAMD, "
131                     "StencilRefLessFrontAMD or StencilRefGreaterFrontAMD "
132                     "execution modes.";
133         }
134         if (execution_modes &&
135             1 < std::count_if(
136                     execution_modes->begin(), execution_modes->end(),
137                     [](const spv::ExecutionMode& mode) {
138                       switch (mode) {
139                         case spv::ExecutionMode::StencilRefUnchangedBackAMD:
140                         case spv::ExecutionMode::StencilRefLessBackAMD:
141                         case spv::ExecutionMode::StencilRefGreaterBackAMD:
142                           return true;
143                         default:
144                           return false;
145                       }
146                     })) {
147           return _.diag(SPV_ERROR_INVALID_DATA, inst)
148                  << "Fragment execution model entry points can specify at most "
149                     "one of StencilRefUnchangedBackAMD, "
150                     "StencilRefLessBackAMD or StencilRefGreaterBackAMD "
151                     "execution modes.";
152         }
153         break;
154       case spv::ExecutionModel::TessellationControl:
155       case spv::ExecutionModel::TessellationEvaluation:
156         if (execution_modes &&
157             1 < std::count_if(
158                     execution_modes->begin(), execution_modes->end(),
159                     [](const spv::ExecutionMode& mode) {
160                       switch (mode) {
161                         case spv::ExecutionMode::SpacingEqual:
162                         case spv::ExecutionMode::SpacingFractionalEven:
163                         case spv::ExecutionMode::SpacingFractionalOdd:
164                           return true;
165                         default:
166                           return false;
167                       }
168                     })) {
169           return _.diag(SPV_ERROR_INVALID_DATA, inst)
170                  << "Tessellation execution model entry points can specify at "
171                     "most one of SpacingEqual, SpacingFractionalOdd or "
172                     "SpacingFractionalEven execution modes.";
173         }
174         if (execution_modes &&
175             1 < std::count_if(execution_modes->begin(), execution_modes->end(),
176                               [](const spv::ExecutionMode& mode) {
177                                 switch (mode) {
178                                   case spv::ExecutionMode::Triangles:
179                                   case spv::ExecutionMode::Quads:
180                                   case spv::ExecutionMode::Isolines:
181                                     return true;
182                                   default:
183                                     return false;
184                                 }
185                               })) {
186           return _.diag(SPV_ERROR_INVALID_DATA, inst)
187                  << "Tessellation execution model entry points can specify at "
188                     "most one of Triangles, Quads or Isolines execution modes.";
189         }
190         if (execution_modes &&
191             1 < std::count_if(execution_modes->begin(), execution_modes->end(),
192                               [](const spv::ExecutionMode& mode) {
193                                 switch (mode) {
194                                   case spv::ExecutionMode::VertexOrderCw:
195                                   case spv::ExecutionMode::VertexOrderCcw:
196                                     return true;
197                                   default:
198                                     return false;
199                                 }
200                               })) {
201           return _.diag(SPV_ERROR_INVALID_DATA, inst)
202                  << "Tessellation execution model entry points can specify at "
203                     "most one of VertexOrderCw or VertexOrderCcw execution "
204                     "modes.";
205         }
206         break;
207       case spv::ExecutionModel::Geometry:
208         if (!execution_modes ||
209             1 != std::count_if(
210                      execution_modes->begin(), execution_modes->end(),
211                      [](const spv::ExecutionMode& mode) {
212                        switch (mode) {
213                          case spv::ExecutionMode::InputPoints:
214                          case spv::ExecutionMode::InputLines:
215                          case spv::ExecutionMode::InputLinesAdjacency:
216                          case spv::ExecutionMode::Triangles:
217                          case spv::ExecutionMode::InputTrianglesAdjacency:
218                            return true;
219                          default:
220                            return false;
221                        }
222                      })) {
223           return _.diag(SPV_ERROR_INVALID_DATA, inst)
224                  << "Geometry execution model entry points must specify "
225                     "exactly one of InputPoints, InputLines, "
226                     "InputLinesAdjacency, Triangles or InputTrianglesAdjacency "
227                     "execution modes.";
228         }
229         if (!execution_modes ||
230             1 != std::count_if(execution_modes->begin(), execution_modes->end(),
231                                [](const spv::ExecutionMode& mode) {
232                                  switch (mode) {
233                                    case spv::ExecutionMode::OutputPoints:
234                                    case spv::ExecutionMode::OutputLineStrip:
235                                    case spv::ExecutionMode::OutputTriangleStrip:
236                                      return true;
237                                    default:
238                                      return false;
239                                  }
240                                })) {
241           return _.diag(SPV_ERROR_INVALID_DATA, inst)
242                  << "Geometry execution model entry points must specify "
243                     "exactly one of OutputPoints, OutputLineStrip or "
244                     "OutputTriangleStrip execution modes.";
245         }
246         break;
247       case spv::ExecutionModel::MeshEXT:
248         if (!execution_modes ||
249             1 != std::count_if(execution_modes->begin(), execution_modes->end(),
250                                [](const spv::ExecutionMode& mode) {
251                                  switch (mode) {
252                                    case spv::ExecutionMode::OutputPoints:
253                                    case spv::ExecutionMode::OutputLinesEXT:
254                                    case spv::ExecutionMode::OutputTrianglesEXT:
255                                      return true;
256                                    default:
257                                      return false;
258                                  }
259                                })) {
260           return _.diag(SPV_ERROR_INVALID_DATA, inst)
261                  << "MeshEXT execution model entry points must specify exactly "
262                     "one of OutputPoints, OutputLinesEXT, or "
263                     "OutputTrianglesEXT Execution Modes.";
264         } else if (2 != std::count_if(
265                             execution_modes->begin(), execution_modes->end(),
266                             [](const spv::ExecutionMode& mode) {
267                               switch (mode) {
268                                 case spv::ExecutionMode::OutputPrimitivesEXT:
269                                 case spv::ExecutionMode::OutputVertices:
270                                   return true;
271                                 default:
272                                   return false;
273                               }
274                             })) {
275           return _.diag(SPV_ERROR_INVALID_DATA, inst)
276                  << "MeshEXT execution model entry points must specify both "
277                     "OutputPrimitivesEXT and OutputVertices Execution Modes.";
278         }
279         break;
280       default:
281         break;
282     }
283   }
284 
285   if (spvIsVulkanEnv(_.context()->target_env)) {
286     switch (execution_model) {
287       case spv::ExecutionModel::GLCompute:
288         if (!execution_modes ||
289             !execution_modes->count(spv::ExecutionMode::LocalSize)) {
290           bool ok = false;
291           for (auto& i : _.ordered_instructions()) {
292             if (i.opcode() == spv::Op::OpDecorate) {
293               if (i.operands().size() > 2) {
294                 if (i.GetOperandAs<spv::Decoration>(1) ==
295                         spv::Decoration::BuiltIn &&
296                     i.GetOperandAs<spv::BuiltIn>(2) ==
297                         spv::BuiltIn::WorkgroupSize) {
298                   ok = true;
299                   break;
300                 }
301               }
302             }
303             if (i.opcode() == spv::Op::OpExecutionModeId) {
304               const auto mode = i.GetOperandAs<spv::ExecutionMode>(1);
305               if (mode == spv::ExecutionMode::LocalSizeId) {
306                 ok = true;
307                 break;
308               }
309             }
310           }
311           if (!ok) {
312             return _.diag(SPV_ERROR_INVALID_DATA, inst)
313                    << _.VkErrorID(6426)
314                    << "In the Vulkan environment, GLCompute execution model "
315                       "entry points require either the LocalSize or "
316                       "LocalSizeId execution mode or an object decorated with "
317                       "WorkgroupSize must be specified.";
318           }
319         }
320         break;
321       default:
322         break;
323     }
324   }
325 
326   return SPV_SUCCESS;
327 }
328 
ValidateExecutionMode(ValidationState_t & _,const Instruction * inst)329 spv_result_t ValidateExecutionMode(ValidationState_t& _,
330                                    const Instruction* inst) {
331   const auto entry_point_id = inst->GetOperandAs<uint32_t>(0);
332   const auto found = std::find(_.entry_points().cbegin(),
333                                _.entry_points().cend(), entry_point_id);
334   if (found == _.entry_points().cend()) {
335     return _.diag(SPV_ERROR_INVALID_ID, inst)
336            << "OpExecutionMode Entry Point <id> " << _.getIdName(entry_point_id)
337            << " is not the Entry Point "
338               "operand of an OpEntryPoint.";
339   }
340 
341   const auto mode = inst->GetOperandAs<spv::ExecutionMode>(1);
342   if (inst->opcode() == spv::Op::OpExecutionModeId) {
343     size_t operand_count = inst->operands().size();
344     for (size_t i = 2; i < operand_count; ++i) {
345       const auto operand_id = inst->GetOperandAs<uint32_t>(2);
346       const auto* operand_inst = _.FindDef(operand_id);
347       if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
348           mode == spv::ExecutionMode::LocalSizeHintId ||
349           mode == spv::ExecutionMode::LocalSizeId) {
350         if (!spvOpcodeIsConstant(operand_inst->opcode())) {
351           return _.diag(SPV_ERROR_INVALID_ID, inst)
352                  << "For OpExecutionModeId all Extra Operand ids must be "
353                     "constant "
354                     "instructions.";
355         }
356       } else {
357         return _.diag(SPV_ERROR_INVALID_ID, inst)
358                << "OpExecutionModeId is only valid when the Mode operand is an "
359                   "execution mode that takes Extra Operands that are id "
360                   "operands.";
361       }
362     }
363   } else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
364              mode == spv::ExecutionMode::LocalSizeHintId ||
365              mode == spv::ExecutionMode::LocalSizeId) {
366     return _.diag(SPV_ERROR_INVALID_DATA, inst)
367            << "OpExecutionMode is only valid when the Mode operand is an "
368               "execution mode that takes no Extra Operands, or takes Extra "
369               "Operands that are not id operands.";
370   }
371 
372   const auto* models = _.GetExecutionModels(entry_point_id);
373   switch (mode) {
374     case spv::ExecutionMode::Invocations:
375     case spv::ExecutionMode::InputPoints:
376     case spv::ExecutionMode::InputLines:
377     case spv::ExecutionMode::InputLinesAdjacency:
378     case spv::ExecutionMode::InputTrianglesAdjacency:
379     case spv::ExecutionMode::OutputLineStrip:
380     case spv::ExecutionMode::OutputTriangleStrip:
381       if (!std::all_of(models->begin(), models->end(),
382                        [](const spv::ExecutionModel& model) {
383                          return model == spv::ExecutionModel::Geometry;
384                        })) {
385         return _.diag(SPV_ERROR_INVALID_DATA, inst)
386                << "Execution mode can only be used with the Geometry execution "
387                   "model.";
388       }
389       break;
390     case spv::ExecutionMode::OutputPoints:
391       if (!std::all_of(
392               models->begin(), models->end(),
393               [&_](const spv::ExecutionModel& model) {
394                 switch (model) {
395                   case spv::ExecutionModel::Geometry:
396                     return true;
397                   case spv::ExecutionModel::MeshNV:
398                     return _.HasCapability(spv::Capability::MeshShadingNV);
399                   case spv::ExecutionModel::MeshEXT:
400                     return _.HasCapability(spv::Capability::MeshShadingEXT);
401                   default:
402                     return false;
403                 }
404               })) {
405         if (_.HasCapability(spv::Capability::MeshShadingNV) ||
406             _.HasCapability(spv::Capability::MeshShadingEXT)) {
407           return _.diag(SPV_ERROR_INVALID_DATA, inst)
408                  << "Execution mode can only be used with the Geometry "
409                     "MeshNV or MeshEXT execution model.";
410         } else {
411           return _.diag(SPV_ERROR_INVALID_DATA, inst)
412                  << "Execution mode can only be used with the Geometry "
413                     "execution "
414                     "model.";
415         }
416       }
417       break;
418     case spv::ExecutionMode::SpacingEqual:
419     case spv::ExecutionMode::SpacingFractionalEven:
420     case spv::ExecutionMode::SpacingFractionalOdd:
421     case spv::ExecutionMode::VertexOrderCw:
422     case spv::ExecutionMode::VertexOrderCcw:
423     case spv::ExecutionMode::PointMode:
424     case spv::ExecutionMode::Quads:
425     case spv::ExecutionMode::Isolines:
426       if (!std::all_of(
427               models->begin(), models->end(),
428               [](const spv::ExecutionModel& model) {
429                 return (model == spv::ExecutionModel::TessellationControl) ||
430                        (model == spv::ExecutionModel::TessellationEvaluation);
431               })) {
432         return _.diag(SPV_ERROR_INVALID_DATA, inst)
433                << "Execution mode can only be used with a tessellation "
434                   "execution model.";
435       }
436       break;
437     case spv::ExecutionMode::Triangles:
438       if (!std::all_of(models->begin(), models->end(),
439                        [](const spv::ExecutionModel& model) {
440                          switch (model) {
441                            case spv::ExecutionModel::Geometry:
442                            case spv::ExecutionModel::TessellationControl:
443                            case spv::ExecutionModel::TessellationEvaluation:
444                              return true;
445                            default:
446                              return false;
447                          }
448                        })) {
449         return _.diag(SPV_ERROR_INVALID_DATA, inst)
450                << "Execution mode can only be used with a Geometry or "
451                   "tessellation execution model.";
452       }
453       break;
454     case spv::ExecutionMode::OutputVertices:
455       if (!std::all_of(
456               models->begin(), models->end(),
457               [&_](const spv::ExecutionModel& model) {
458                 switch (model) {
459                   case spv::ExecutionModel::Geometry:
460                   case spv::ExecutionModel::TessellationControl:
461                   case spv::ExecutionModel::TessellationEvaluation:
462                     return true;
463                   case spv::ExecutionModel::MeshNV:
464                     return _.HasCapability(spv::Capability::MeshShadingNV);
465                   case spv::ExecutionModel::MeshEXT:
466                     return _.HasCapability(spv::Capability::MeshShadingEXT);
467                   default:
468                     return false;
469                 }
470               })) {
471         if (_.HasCapability(spv::Capability::MeshShadingNV) ||
472             _.HasCapability(spv::Capability::MeshShadingEXT)) {
473           return _.diag(SPV_ERROR_INVALID_DATA, inst)
474                  << "Execution mode can only be used with a Geometry, "
475                     "tessellation, MeshNV or MeshEXT execution model.";
476         } else {
477           return _.diag(SPV_ERROR_INVALID_DATA, inst)
478                  << "Execution mode can only be used with a Geometry or "
479                     "tessellation execution model.";
480         }
481       }
482       break;
483     case spv::ExecutionMode::OutputLinesEXT:
484     case spv::ExecutionMode::OutputTrianglesEXT:
485     case spv::ExecutionMode::OutputPrimitivesEXT:
486       if (!std::all_of(models->begin(), models->end(),
487                        [](const spv::ExecutionModel& model) {
488                          return (model == spv::ExecutionModel::MeshEXT ||
489                                  model == spv::ExecutionModel::MeshNV);
490                        })) {
491         return _.diag(SPV_ERROR_INVALID_DATA, inst)
492                << "Execution mode can only be used with the MeshEXT or MeshNV "
493                   "execution "
494                   "model.";
495       }
496       break;
497     case spv::ExecutionMode::PixelCenterInteger:
498     case spv::ExecutionMode::OriginUpperLeft:
499     case spv::ExecutionMode::OriginLowerLeft:
500     case spv::ExecutionMode::EarlyFragmentTests:
501     case spv::ExecutionMode::DepthReplacing:
502     case spv::ExecutionMode::DepthGreater:
503     case spv::ExecutionMode::DepthLess:
504     case spv::ExecutionMode::DepthUnchanged:
505     case spv::ExecutionMode::NonCoherentColorAttachmentReadEXT:
506     case spv::ExecutionMode::NonCoherentDepthAttachmentReadEXT:
507     case spv::ExecutionMode::NonCoherentStencilAttachmentReadEXT:
508     case spv::ExecutionMode::PixelInterlockOrderedEXT:
509     case spv::ExecutionMode::PixelInterlockUnorderedEXT:
510     case spv::ExecutionMode::SampleInterlockOrderedEXT:
511     case spv::ExecutionMode::SampleInterlockUnorderedEXT:
512     case spv::ExecutionMode::ShadingRateInterlockOrderedEXT:
513     case spv::ExecutionMode::ShadingRateInterlockUnorderedEXT:
514     case spv::ExecutionMode::EarlyAndLateFragmentTestsAMD:
515     case spv::ExecutionMode::StencilRefUnchangedFrontAMD:
516     case spv::ExecutionMode::StencilRefGreaterFrontAMD:
517     case spv::ExecutionMode::StencilRefLessFrontAMD:
518     case spv::ExecutionMode::StencilRefUnchangedBackAMD:
519     case spv::ExecutionMode::StencilRefGreaterBackAMD:
520     case spv::ExecutionMode::StencilRefLessBackAMD:
521       if (!std::all_of(models->begin(), models->end(),
522                        [](const spv::ExecutionModel& model) {
523                          return model == spv::ExecutionModel::Fragment;
524                        })) {
525         return _.diag(SPV_ERROR_INVALID_DATA, inst)
526                << "Execution mode can only be used with the Fragment execution "
527                   "model.";
528       }
529       break;
530     case spv::ExecutionMode::LocalSizeHint:
531     case spv::ExecutionMode::VecTypeHint:
532     case spv::ExecutionMode::ContractionOff:
533     case spv::ExecutionMode::LocalSizeHintId:
534       if (!std::all_of(models->begin(), models->end(),
535                        [](const spv::ExecutionModel& model) {
536                          return model == spv::ExecutionModel::Kernel;
537                        })) {
538         return _.diag(SPV_ERROR_INVALID_DATA, inst)
539                << "Execution mode can only be used with the Kernel execution "
540                   "model.";
541       }
542       break;
543     case spv::ExecutionMode::LocalSize:
544     case spv::ExecutionMode::LocalSizeId:
545       if (mode == spv::ExecutionMode::LocalSizeId && !_.IsLocalSizeIdAllowed())
546         return _.diag(SPV_ERROR_INVALID_DATA, inst)
547                << "LocalSizeId mode is not allowed by the current environment.";
548 
549       if (!std::all_of(
550               models->begin(), models->end(),
551               [&_](const spv::ExecutionModel& model) {
552                 switch (model) {
553                   case spv::ExecutionModel::Kernel:
554                   case spv::ExecutionModel::GLCompute:
555                     return true;
556                   case spv::ExecutionModel::TaskNV:
557                   case spv::ExecutionModel::MeshNV:
558                     return _.HasCapability(spv::Capability::MeshShadingNV);
559                   case spv::ExecutionModel::TaskEXT:
560                   case spv::ExecutionModel::MeshEXT:
561                     return _.HasCapability(spv::Capability::MeshShadingEXT);
562                   default:
563                     return false;
564                 }
565               })) {
566         if (_.HasCapability(spv::Capability::MeshShadingNV) ||
567             _.HasCapability(spv::Capability::MeshShadingEXT)) {
568           return _.diag(SPV_ERROR_INVALID_DATA, inst)
569                  << "Execution mode can only be used with a Kernel, GLCompute, "
570                     "MeshNV, MeshEXT, TaskNV or TaskEXT execution model.";
571         } else {
572           return _.diag(SPV_ERROR_INVALID_DATA, inst)
573                  << "Execution mode can only be used with a Kernel or "
574                     "GLCompute "
575                     "execution model.";
576         }
577       }
578     default:
579       break;
580   }
581 
582   if (spvIsVulkanEnv(_.context()->target_env)) {
583     if (mode == spv::ExecutionMode::OriginLowerLeft) {
584       return _.diag(SPV_ERROR_INVALID_DATA, inst)
585              << _.VkErrorID(4653)
586              << "In the Vulkan environment, the OriginLowerLeft execution mode "
587                 "must not be used.";
588     }
589     if (mode == spv::ExecutionMode::PixelCenterInteger) {
590       return _.diag(SPV_ERROR_INVALID_DATA, inst)
591              << _.VkErrorID(4654)
592              << "In the Vulkan environment, the PixelCenterInteger execution "
593                 "mode must not be used.";
594     }
595   }
596 
597   return SPV_SUCCESS;
598 }
599 
ValidateMemoryModel(ValidationState_t & _,const Instruction * inst)600 spv_result_t ValidateMemoryModel(ValidationState_t& _,
601                                  const Instruction* inst) {
602   // Already produced an error if multiple memory model instructions are
603   // present.
604   if (_.memory_model() != spv::MemoryModel::VulkanKHR &&
605       _.HasCapability(spv::Capability::VulkanMemoryModelKHR)) {
606     return _.diag(SPV_ERROR_INVALID_DATA, inst)
607            << "VulkanMemoryModelKHR capability must only be specified if "
608               "the VulkanKHR memory model is used.";
609   }
610 
611   if (spvIsOpenCLEnv(_.context()->target_env)) {
612     if ((_.addressing_model() != spv::AddressingModel::Physical32) &&
613         (_.addressing_model() != spv::AddressingModel::Physical64)) {
614       return _.diag(SPV_ERROR_INVALID_DATA, inst)
615              << "Addressing model must be Physical32 or Physical64 "
616              << "in the OpenCL environment.";
617     }
618     if (_.memory_model() != spv::MemoryModel::OpenCL) {
619       return _.diag(SPV_ERROR_INVALID_DATA, inst)
620              << "Memory model must be OpenCL in the OpenCL environment.";
621     }
622   }
623 
624   if (spvIsVulkanEnv(_.context()->target_env)) {
625     if ((_.addressing_model() != spv::AddressingModel::Logical) &&
626         (_.addressing_model() !=
627          spv::AddressingModel::PhysicalStorageBuffer64)) {
628       return _.diag(SPV_ERROR_INVALID_DATA, inst)
629              << _.VkErrorID(4635)
630              << "Addressing model must be Logical or PhysicalStorageBuffer64 "
631              << "in the Vulkan environment.";
632     }
633   }
634   return SPV_SUCCESS;
635 }
636 
637 }  // namespace
638 
ModeSettingPass(ValidationState_t & _,const Instruction * inst)639 spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
640   switch (inst->opcode()) {
641     case spv::Op::OpEntryPoint:
642       if (auto error = ValidateEntryPoint(_, inst)) return error;
643       break;
644     case spv::Op::OpExecutionMode:
645     case spv::Op::OpExecutionModeId:
646       if (auto error = ValidateExecutionMode(_, inst)) return error;
647       break;
648     case spv::Op::OpMemoryModel:
649       if (auto error = ValidateMemoryModel(_, inst)) return error;
650       break;
651     default:
652       break;
653   }
654   return SPV_SUCCESS;
655 }
656 
657 }  // namespace val
658 }  // namespace spvtools
659