Home | History | Annotate | Download | only in source
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      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 "validate.h"
     16 
     17 #include <cassert>
     18 
     19 #include <algorithm>
     20 #include <iostream>
     21 #include <unordered_set>
     22 #include <utility>
     23 #include <vector>
     24 
     25 #include "diagnostic.h"
     26 #include "instruction.h"
     27 #include "message.h"
     28 #include "opcode.h"
     29 #include "spirv_validator_options.h"
     30 #include "spirv-tools/libspirv.h"
     31 #include "val/function.h"
     32 #include "val/validation_state.h"
     33 
     34 using libspirv::ValidationState_t;
     35 using libspirv::Decoration;
     36 using std::function;
     37 using std::ignore;
     38 using std::make_pair;
     39 using std::pair;
     40 using std::unordered_set;
     41 using std::vector;
     42 
     43 namespace {
     44 
     45 class idUsage {
     46  public:
     47   idUsage(const spv_opcode_table opcodeTableArg,
     48           const spv_operand_table operandTableArg,
     49           const spv_ext_inst_table extInstTableArg,
     50           const spv_instruction_t* pInsts, const uint64_t instCountArg,
     51           const SpvMemoryModel memoryModelArg,
     52           const SpvAddressingModel addressingModelArg,
     53           const ValidationState_t& module, const vector<uint32_t>& entry_points,
     54           spv_position positionArg, const spvtools::MessageConsumer& consumer)
     55       : opcodeTable(opcodeTableArg),
     56         operandTable(operandTableArg),
     57         extInstTable(extInstTableArg),
     58         firstInst(pInsts),
     59         instCount(instCountArg),
     60         memoryModel(memoryModelArg),
     61         addressingModel(addressingModelArg),
     62         position(positionArg),
     63         consumer_(consumer),
     64         module_(module),
     65         entry_points_(entry_points) {}
     66 
     67   bool isValid(const spv_instruction_t* inst);
     68 
     69   template <SpvOp>
     70   bool isValid(const spv_instruction_t* inst, const spv_opcode_desc);
     71 
     72  private:
     73   const spv_opcode_table opcodeTable;
     74   const spv_operand_table operandTable;
     75   const spv_ext_inst_table extInstTable;
     76   const spv_instruction_t* const firstInst;
     77   const uint64_t instCount;
     78   const SpvMemoryModel memoryModel;
     79   const SpvAddressingModel addressingModel;
     80   spv_position position;
     81   const spvtools::MessageConsumer& consumer_;
     82   const ValidationState_t& module_;
     83   vector<uint32_t> entry_points_;
     84 };
     85 
     86 #define DIAG(INDEX)                                                \
     87   position->index += INDEX;                                        \
     88   libspirv::DiagnosticStream helper(*position, consumer_,          \
     89                                     SPV_ERROR_INVALID_DIAGNOSTIC); \
     90   helper
     91 
     92 #if 0
     93 template <>
     94 bool idUsage::isValid<SpvOpUndef>(const spv_instruction_t *inst,
     95                                   const spv_opcode_desc) {
     96   assert(0 && "Unimplemented!");
     97   return false;
     98 }
     99 #endif  // 0
    100 
    101 template <>
    102 bool idUsage::isValid<SpvOpMemberName>(const spv_instruction_t* inst,
    103                                        const spv_opcode_desc) {
    104   auto typeIndex = 1;
    105   auto type = module_.FindDef(inst->words[typeIndex]);
    106   if (!type || SpvOpTypeStruct != type->opcode()) {
    107     DIAG(typeIndex) << "OpMemberName Type <id> '" << inst->words[typeIndex]
    108                     << "' is not a struct type.";
    109     return false;
    110   }
    111   auto memberIndex = 2;
    112   auto member = inst->words[memberIndex];
    113   auto memberCount = (uint32_t)(type->words().size() - 2);
    114   if (memberCount <= member) {
    115     DIAG(memberIndex) << "OpMemberName Member <id> '"
    116                       << inst->words[memberIndex]
    117                       << "' index is larger than Type <id> '" << type->id()
    118                       << "'s member count.";
    119     return false;
    120   }
    121   return true;
    122 }
    123 
    124 template <>
    125 bool idUsage::isValid<SpvOpLine>(const spv_instruction_t* inst,
    126                                  const spv_opcode_desc) {
    127   auto fileIndex = 1;
    128   auto file = module_.FindDef(inst->words[fileIndex]);
    129   if (!file || SpvOpString != file->opcode()) {
    130     DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
    131                     << "' is not an OpString.";
    132     return false;
    133   }
    134   return true;
    135 }
    136 
    137 template <>
    138 bool idUsage::isValid<SpvOpDecorate>(const spv_instruction_t* inst,
    139                                      const spv_opcode_desc) {
    140   auto decorationIndex = 2;
    141   auto decoration = inst->words[decorationIndex];
    142   if (decoration == SpvDecorationSpecId) {
    143     auto targetIndex = 1;
    144     auto target = module_.FindDef(inst->words[targetIndex]);
    145     if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) {
    146       DIAG(targetIndex) << "OpDecorate SpectId decoration target <id> '"
    147                         << inst->words[decorationIndex]
    148                         << "' is not a scalar specialization constant.";
    149       return false;
    150     }
    151   }
    152   // TODO: Add validations for all decorations.
    153   return true;
    154 }
    155 
    156 template <>
    157 bool idUsage::isValid<SpvOpMemberDecorate>(const spv_instruction_t* inst,
    158                                            const spv_opcode_desc) {
    159   auto structTypeIndex = 1;
    160   auto structType = module_.FindDef(inst->words[structTypeIndex]);
    161   if (!structType || SpvOpTypeStruct != structType->opcode()) {
    162     DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
    163                           << inst->words[structTypeIndex]
    164                           << "' is not a struct type.";
    165     return false;
    166   }
    167   auto memberIndex = 2;
    168   auto member = inst->words[memberIndex];
    169   auto memberCount = static_cast<uint32_t>(structType->words().size() - 2);
    170   if (memberCount < member) {
    171     DIAG(memberIndex) << "Index " << member
    172                       << " provided in OpMemberDecorate for struct <id> "
    173                       << inst->words[structTypeIndex]
    174                       << " is out of bounds. The structure has " << memberCount
    175                       << " members. Largest valid index is " << memberCount - 1
    176                       << ".";
    177     return false;
    178   }
    179   return true;
    180 }
    181 
    182 template <>
    183 bool idUsage::isValid<SpvOpGroupDecorate>(const spv_instruction_t* inst,
    184                                           const spv_opcode_desc) {
    185   auto decorationGroupIndex = 1;
    186   auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
    187   if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) {
    188     DIAG(decorationGroupIndex) << "OpGroupDecorate Decoration group <id> '"
    189                                << inst->words[decorationGroupIndex]
    190                                << "' is not a decoration group.";
    191     return false;
    192   }
    193   return true;
    194 }
    195 
    196 template <>
    197 bool idUsage::isValid<SpvOpGroupMemberDecorate>(
    198     const spv_instruction_t* inst, const spv_opcode_desc) {
    199   auto decorationGroupIndex = 1;
    200   auto decorationGroup = module_.FindDef(inst->words[decorationGroupIndex]);
    201   if (!decorationGroup || SpvOpDecorationGroup != decorationGroup->opcode()) {
    202     DIAG(decorationGroupIndex)
    203         << "OpGroupMemberDecorate Decoration group <id> '"
    204         << inst->words[decorationGroupIndex] << "' is not a decoration group.";
    205     return false;
    206   }
    207   // Grammar checks ensures that the number of arguments to this instruction
    208   // is an odd number: 1 decoration group + (id,literal) pairs.
    209   for (size_t i = 2; i + 1 < inst->words.size(); i = i + 2) {
    210     const uint32_t struct_id = inst->words[i];
    211     const uint32_t index = inst->words[i + 1];
    212     auto struct_instr = module_.FindDef(struct_id);
    213     if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) {
    214       DIAG(i) << "OpGroupMemberDecorate Structure type <id> '" << struct_id
    215               << "' is not a struct type.";
    216       return false;
    217     }
    218     const uint32_t num_struct_members =
    219         static_cast<uint32_t>(struct_instr->words().size() - 2);
    220     if (index >= num_struct_members) {
    221       DIAG(i) << "Index " << index
    222               << " provided in OpGroupMemberDecorate for struct <id> "
    223               << struct_id << " is out of bounds. The structure has "
    224               << num_struct_members << " members. Largest valid index is "
    225               << num_struct_members - 1 << ".";
    226       return false;
    227     }
    228   }
    229   return true;
    230 }
    231 
    232 #if 0
    233 template <>
    234 bool idUsage::isValid<SpvOpExtInst>(const spv_instruction_t *inst,
    235                                     const spv_opcode_desc opcodeEntry) {}
    236 #endif  // 0
    237 
    238 template <>
    239 bool idUsage::isValid<SpvOpEntryPoint>(const spv_instruction_t* inst,
    240                                        const spv_opcode_desc) {
    241   auto entryPointIndex = 2;
    242   auto entryPoint = module_.FindDef(inst->words[entryPointIndex]);
    243   if (!entryPoint || SpvOpFunction != entryPoint->opcode()) {
    244     DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    245                           << inst->words[entryPointIndex]
    246                           << "' is not a function.";
    247     return false;
    248   }
    249   // don't check kernel function signatures
    250   auto executionModel = inst->words[1];
    251   if (executionModel != SpvExecutionModelKernel) {
    252     // TODO: Check the entry point signature is void main(void), may be subject
    253     // to change
    254     auto entryPointType = module_.FindDef(entryPoint->words()[4]);
    255     if (!entryPointType || 3 != entryPointType->words().size()) {
    256       DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    257                             << inst->words[entryPointIndex]
    258                             << "'s function parameter count is not zero.";
    259       return false;
    260     }
    261   }
    262   auto returnType = module_.FindDef(entryPoint->type_id());
    263   if (!returnType || SpvOpTypeVoid != returnType->opcode()) {
    264     DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    265                           << inst->words[entryPointIndex]
    266                           << "'s function return type is not void.";
    267     return false;
    268   }
    269   return true;
    270 }
    271 
    272 template <>
    273 bool idUsage::isValid<SpvOpExecutionMode>(const spv_instruction_t* inst,
    274                                           const spv_opcode_desc) {
    275   auto entryPointIndex = 1;
    276   auto entryPointID = inst->words[entryPointIndex];
    277   auto found =
    278       std::find(entry_points_.cbegin(), entry_points_.cend(), entryPointID);
    279   if (found == entry_points_.cend()) {
    280     DIAG(entryPointIndex) << "OpExecutionMode Entry Point <id> '"
    281                           << inst->words[entryPointIndex]
    282                           << "' is not the Entry Point "
    283                              "operand of an OpEntryPoint.";
    284     return false;
    285   }
    286   return true;
    287 }
    288 
    289 template <>
    290 bool idUsage::isValid<SpvOpTypeVector>(const spv_instruction_t* inst,
    291                                        const spv_opcode_desc) {
    292   auto componentIndex = 2;
    293   auto componentType = module_.FindDef(inst->words[componentIndex]);
    294   if (!componentType || !spvOpcodeIsScalarType(componentType->opcode())) {
    295     DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
    296                          << inst->words[componentIndex]
    297                          << "' is not a scalar type.";
    298     return false;
    299   }
    300   return true;
    301 }
    302 
    303 template <>
    304 bool idUsage::isValid<SpvOpTypeMatrix>(const spv_instruction_t* inst,
    305                                        const spv_opcode_desc) {
    306   auto columnTypeIndex = 2;
    307   auto columnType = module_.FindDef(inst->words[columnTypeIndex]);
    308   if (!columnType || SpvOpTypeVector != columnType->opcode()) {
    309     DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
    310                           << inst->words[columnTypeIndex]
    311                           << "' is not a vector.";
    312     return false;
    313   }
    314   return true;
    315 }
    316 
    317 template <>
    318 bool idUsage::isValid<SpvOpTypeSampler>(const spv_instruction_t*,
    319                                         const spv_opcode_desc) {
    320   // OpTypeSampler takes no arguments in Rev31 and beyond.
    321   return true;
    322 }
    323 
    324 // True if the integer constant is > 0. constWords are words of the
    325 // constant-defining instruction (either OpConstant or
    326 // OpSpecConstant). typeWords are the words of the constant's-type-defining
    327 // OpTypeInt.
    328 bool aboveZero(const vector<uint32_t>& constWords,
    329                const vector<uint32_t>& typeWords) {
    330   const uint32_t width = typeWords[2];
    331   const bool is_signed = typeWords[3] > 0;
    332   const uint32_t loWord = constWords[3];
    333   if (width > 32) {
    334     // The spec currently doesn't allow integers wider than 64 bits.
    335     const uint32_t hiWord = constWords[4];  // Must exist, per spec.
    336     if (is_signed && (hiWord >> 31)) return false;
    337     return (loWord | hiWord) > 0;
    338   } else {
    339     if (is_signed && (loWord >> 31)) return false;
    340     return loWord > 0;
    341   }
    342 }
    343 
    344 template <>
    345 bool idUsage::isValid<SpvOpTypeArray>(const spv_instruction_t* inst,
    346                                       const spv_opcode_desc) {
    347   auto elementTypeIndex = 2;
    348   auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
    349   if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
    350     DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
    351                            << inst->words[elementTypeIndex]
    352                            << "' is not a type.";
    353     return false;
    354   }
    355   auto lengthIndex = 3;
    356   auto length = module_.FindDef(inst->words[lengthIndex]);
    357   if (!length || !spvOpcodeIsConstant(length->opcode())) {
    358     DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
    359                       << "' is not a scalar constant type.";
    360     return false;
    361   }
    362 
    363   // NOTE: Check the initialiser value of the constant
    364   auto constInst = length->words();
    365   auto constResultTypeIndex = 1;
    366   auto constResultType = module_.FindDef(constInst[constResultTypeIndex]);
    367   if (!constResultType || SpvOpTypeInt != constResultType->opcode()) {
    368     DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
    369                       << "' is not a constant integer type.";
    370     return false;
    371   }
    372 
    373   switch (length->opcode()) {
    374     case SpvOpSpecConstant:
    375     case SpvOpConstant:
    376       if (aboveZero(length->words(), constResultType->words())) break;
    377     // Else fall through!
    378     case SpvOpConstantNull: {
    379       DIAG(lengthIndex) << "OpTypeArray Length <id> '"
    380                         << inst->words[lengthIndex]
    381                         << "' default value must be at least 1.";
    382       return false;
    383     }
    384     case SpvOpSpecConstantOp:
    385       // Assume it's OK, rather than try to evaluate the operation.
    386       break;
    387     default:
    388       assert(0 && "bug in spvOpcodeIsConstant() or result type isn't int");
    389   }
    390   return true;
    391 }
    392 
    393 template <>
    394 bool idUsage::isValid<SpvOpTypeRuntimeArray>(const spv_instruction_t* inst,
    395                                              const spv_opcode_desc) {
    396   auto elementTypeIndex = 2;
    397   auto elementType = module_.FindDef(inst->words[elementTypeIndex]);
    398   if (!elementType || !spvOpcodeGeneratesType(elementType->opcode())) {
    399     DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
    400                            << inst->words[elementTypeIndex]
    401                            << "' is not a type.";
    402     return false;
    403   }
    404   return true;
    405 }
    406 
    407 template <>
    408 bool idUsage::isValid<SpvOpTypeStruct>(const spv_instruction_t* inst,
    409                                        const spv_opcode_desc) {
    410   ValidationState_t& vstate = const_cast<ValidationState_t&>(module_);
    411   const uint32_t struct_id = inst->words[1];
    412   for (size_t memberTypeIndex = 2; memberTypeIndex < inst->words.size();
    413        ++memberTypeIndex) {
    414     auto memberTypeId = inst->words[memberTypeIndex];
    415     auto memberType = module_.FindDef(memberTypeId);
    416     if (!memberType || !spvOpcodeGeneratesType(memberType->opcode())) {
    417       DIAG(memberTypeIndex) << "OpTypeStruct Member Type <id> '"
    418                             << inst->words[memberTypeIndex]
    419                             << "' is not a type.";
    420       return false;
    421     }
    422     if (SpvOpTypeStruct == memberType->opcode() &&
    423         module_.IsStructTypeWithBuiltInMember(memberTypeId)) {
    424       DIAG(memberTypeIndex)
    425           << "Structure <id> " << memberTypeId
    426           << " contains members with BuiltIn decoration. Therefore this "
    427              "structure may not be contained as a member of another structure "
    428              "type. Structure <id> "
    429           << struct_id << " contains structure <id> " << memberTypeId << ".";
    430       return false;
    431     }
    432     if (module_.IsForwardPointer(memberTypeId)) {
    433       if (memberType->opcode() != SpvOpTypePointer) {
    434         DIAG(memberTypeIndex) << "Found a forward reference to a non-pointer "
    435                                  "type in OpTypeStruct instruction.";
    436         return false;
    437       }
    438       // If we're dealing with a forward pointer:
    439       // Find out the type that the pointer is pointing to (must be struct)
    440       // word 3 is the <id> of the type being pointed to.
    441       auto typePointingTo = module_.FindDef(memberType->words()[3]);
    442       if (typePointingTo && typePointingTo->opcode() != SpvOpTypeStruct) {
    443         // Forward declared operands of a struct may only point to a struct.
    444         DIAG(memberTypeIndex)
    445             << "A forward reference operand in an OpTypeStruct must be an "
    446                "OpTypePointer that points to an OpTypeStruct. "
    447                "Found OpTypePointer that points to Op"
    448             << spvOpcodeString(static_cast<SpvOp>(typePointingTo->opcode()))
    449             << ".";
    450         return false;
    451       }
    452     }
    453   }
    454   std::unordered_set<uint32_t> built_in_members;
    455   for (auto decoration : vstate.id_decorations(struct_id)) {
    456     if (decoration.dec_type() == SpvDecorationBuiltIn &&
    457         decoration.struct_member_index() != Decoration::kInvalidMember) {
    458       built_in_members.insert(decoration.struct_member_index());
    459     }
    460   }
    461   int num_struct_members = static_cast<int>(inst->words.size() - 2);
    462   int num_builtin_members = static_cast<int>(built_in_members.size());
    463   if (num_builtin_members > 0 && num_builtin_members != num_struct_members) {
    464     DIAG(0)
    465         << "When BuiltIn decoration is applied to a structure-type member, "
    466            "all members of that structure type must also be decorated with "
    467            "BuiltIn (No allowed mixing of built-in variables and "
    468            "non-built-in variables within a single structure). Structure id "
    469         << struct_id << " does not meet this requirement.";
    470     return false;
    471   }
    472   if (num_builtin_members > 0) {
    473     vstate.RegisterStructTypeWithBuiltInMember(struct_id);
    474   }
    475   return true;
    476 }
    477 
    478 template <>
    479 bool idUsage::isValid<SpvOpTypePointer>(const spv_instruction_t* inst,
    480                                         const spv_opcode_desc) {
    481   auto typeIndex = 3;
    482   auto type = module_.FindDef(inst->words[typeIndex]);
    483   if (!type || !spvOpcodeGeneratesType(type->opcode())) {
    484     DIAG(typeIndex) << "OpTypePointer Type <id> '" << inst->words[typeIndex]
    485                     << "' is not a type.";
    486     return false;
    487   }
    488   return true;
    489 }
    490 
    491 template <>
    492 bool idUsage::isValid<SpvOpTypeFunction>(const spv_instruction_t* inst,
    493                                          const spv_opcode_desc) {
    494   auto returnTypeIndex = 2;
    495   auto returnType = module_.FindDef(inst->words[returnTypeIndex]);
    496   if (!returnType || !spvOpcodeGeneratesType(returnType->opcode())) {
    497     DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
    498                           << inst->words[returnTypeIndex] << "' is not a type.";
    499     return false;
    500   }
    501   size_t num_args = 0;
    502   for (size_t paramTypeIndex = 3; paramTypeIndex < inst->words.size();
    503        ++paramTypeIndex, ++num_args) {
    504     auto paramType = module_.FindDef(inst->words[paramTypeIndex]);
    505     if (!paramType || !spvOpcodeGeneratesType(paramType->opcode())) {
    506       DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
    507                            << inst->words[paramTypeIndex] << "' is not a type.";
    508       return false;
    509     }
    510   }
    511   const uint32_t num_function_args_limit =
    512       module_.options()->universal_limits_.max_function_args;
    513   if (num_args > num_function_args_limit) {
    514     DIAG(returnTypeIndex) << "OpTypeFunction may not take more than "
    515                           << num_function_args_limit
    516                           << " arguments. OpTypeFunction <id> '"
    517                           << inst->words[1] << "' has " << num_args
    518                           << " arguments.";
    519     return false;
    520   }
    521   return true;
    522 }
    523 
    524 template <>
    525 bool idUsage::isValid<SpvOpTypePipe>(const spv_instruction_t*,
    526                                      const spv_opcode_desc) {
    527   // OpTypePipe has no ID arguments.
    528   return true;
    529 }
    530 
    531 template <>
    532 bool idUsage::isValid<SpvOpConstantTrue>(const spv_instruction_t* inst,
    533                                          const spv_opcode_desc) {
    534   auto resultTypeIndex = 1;
    535   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    536   if (!resultType || SpvOpTypeBool != resultType->opcode()) {
    537     DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
    538                           << inst->words[resultTypeIndex]
    539                           << "' is not a boolean type.";
    540     return false;
    541   }
    542   return true;
    543 }
    544 
    545 template <>
    546 bool idUsage::isValid<SpvOpConstantFalse>(const spv_instruction_t* inst,
    547                                           const spv_opcode_desc) {
    548   auto resultTypeIndex = 1;
    549   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    550   if (!resultType || SpvOpTypeBool != resultType->opcode()) {
    551     DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
    552                           << inst->words[resultTypeIndex]
    553                           << "' is not a boolean type.";
    554     return false;
    555   }
    556   return true;
    557 }
    558 
    559 template <>
    560 bool idUsage::isValid<SpvOpConstantComposite>(const spv_instruction_t* inst,
    561                                               const spv_opcode_desc) {
    562   auto resultTypeIndex = 1;
    563   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    564   if (!resultType || !spvOpcodeIsComposite(resultType->opcode())) {
    565     DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
    566                           << inst->words[resultTypeIndex]
    567                           << "' is not a composite type.";
    568     return false;
    569   }
    570 
    571   auto constituentCount = inst->words.size() - 3;
    572   switch (resultType->opcode()) {
    573     case SpvOpTypeVector: {
    574       auto componentCount = resultType->words()[3];
    575       if (componentCount != constituentCount) {
    576         // TODO: Output ID's on diagnostic
    577         DIAG(inst->words.size() - 1)
    578             << "OpConstantComposite Constituent <id> count does not match "
    579                "Result Type <id> '"
    580             << resultType->id() << "'s vector component count.";
    581         return false;
    582       }
    583       auto componentType = module_.FindDef(resultType->words()[2]);
    584       assert(componentType);
    585       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    586            constituentIndex++) {
    587         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    588         if (!constituent ||
    589             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
    590           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    591                                  << inst->words[constituentIndex]
    592                                  << "' is not a constant or undef.";
    593           return false;
    594         }
    595         auto constituentResultType = module_.FindDef(constituent->type_id());
    596         if (!constituentResultType ||
    597             componentType->opcode() != constituentResultType->opcode()) {
    598           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    599                                  << inst->words[constituentIndex]
    600                                  << "'s type does not match Result Type <id> '"
    601                                  << resultType->id()
    602                                  << "'s vector element type.";
    603           return false;
    604         }
    605       }
    606     } break;
    607     case SpvOpTypeMatrix: {
    608       auto columnCount = resultType->words()[3];
    609       if (columnCount != constituentCount) {
    610         // TODO: Output ID's on diagnostic
    611         DIAG(inst->words.size() - 1)
    612             << "OpConstantComposite Constituent <id> count does not match "
    613                "Result Type <id> '"
    614             << resultType->id() << "'s matrix column count.";
    615         return false;
    616       }
    617 
    618       auto columnType = module_.FindDef(resultType->words()[2]);
    619       assert(columnType);
    620       auto componentCount = columnType->words()[3];
    621       auto componentType = module_.FindDef(columnType->words()[2]);
    622       assert(componentType);
    623 
    624       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    625            constituentIndex++) {
    626         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    627         if (!constituent ||
    628             !(SpvOpConstantComposite == constituent->opcode() ||
    629               SpvOpUndef == constituent->opcode())) {
    630           // The message says "... or undef" because the spec does not say
    631           // undef is a constant.
    632           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    633                                  << inst->words[constituentIndex]
    634                                  << "' is not a constant composite or undef.";
    635           return false;
    636         }
    637         auto vector = module_.FindDef(constituent->type_id());
    638         assert(vector);
    639         if (columnType->opcode() != vector->opcode()) {
    640           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    641                                  << inst->words[constituentIndex]
    642                                  << "' type does not match Result Type <id> '"
    643                                  << resultType->id()
    644                                  << "'s matrix column type.";
    645           return false;
    646         }
    647         auto vectorComponentType = module_.FindDef(vector->words()[2]);
    648         assert(vectorComponentType);
    649         if (componentType->id() != vectorComponentType->id()) {
    650           DIAG(constituentIndex)
    651               << "OpConstantComposite Constituent <id> '"
    652               << inst->words[constituentIndex]
    653               << "' component type does not match Result Type <id> '"
    654               << resultType->id() << "'s matrix column component type.";
    655           return false;
    656         }
    657         if (componentCount != vector->words()[3]) {
    658           DIAG(constituentIndex)
    659               << "OpConstantComposite Constituent <id> '"
    660               << inst->words[constituentIndex]
    661               << "' vector component count does not match Result Type <id> '"
    662               << resultType->id() << "'s vector component count.";
    663           return false;
    664         }
    665       }
    666     } break;
    667     case SpvOpTypeArray: {
    668       auto elementType = module_.FindDef(resultType->words()[2]);
    669       assert(elementType);
    670       auto length = module_.FindDef(resultType->words()[3]);
    671       assert(length);
    672       if (length->words()[3] != constituentCount) {
    673         DIAG(inst->words.size() - 1)
    674             << "OpConstantComposite Constituent count does not match "
    675                "Result Type <id> '"
    676             << resultType->id() << "'s array length.";
    677         return false;
    678       }
    679       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    680            constituentIndex++) {
    681         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    682         if (!constituent ||
    683             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
    684           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    685                                  << inst->words[constituentIndex]
    686                                  << "' is not a constant or undef.";
    687           return false;
    688         }
    689         auto constituentType = module_.FindDef(constituent->type_id());
    690         assert(constituentType);
    691         if (elementType->id() != constituentType->id()) {
    692           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    693                                  << inst->words[constituentIndex]
    694                                  << "'s type does not match Result Type <id> '"
    695                                  << resultType->id()
    696                                  << "'s array element type.";
    697           return false;
    698         }
    699       }
    700     } break;
    701     case SpvOpTypeStruct: {
    702       auto memberCount = resultType->words().size() - 2;
    703       if (memberCount != constituentCount) {
    704         DIAG(resultTypeIndex) << "OpConstantComposite Constituent <id> '"
    705                               << inst->words[resultTypeIndex]
    706                               << "' count does not match Result Type <id> '"
    707                               << resultType->id() << "'s struct member count.";
    708         return false;
    709       }
    710       for (uint32_t constituentIndex = 3, memberIndex = 2;
    711            constituentIndex < inst->words.size();
    712            constituentIndex++, memberIndex++) {
    713         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    714         if (!constituent ||
    715             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
    716           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    717                                  << inst->words[constituentIndex]
    718                                  << "' is not a constant or undef.";
    719           return false;
    720         }
    721         auto constituentType = module_.FindDef(constituent->type_id());
    722         assert(constituentType);
    723 
    724         auto memberType = module_.FindDef(resultType->words()[memberIndex]);
    725         assert(memberType);
    726         if (memberType->id() != constituentType->id()) {
    727           DIAG(constituentIndex)
    728               << "OpConstantComposite Constituent <id> '"
    729               << inst->words[constituentIndex]
    730               << "' type does not match the Result Type <id> '"
    731               << resultType->id() << "'s member type.";
    732           return false;
    733         }
    734       }
    735     } break;
    736     default: { assert(0 && "Unreachable!"); } break;
    737   }
    738   return true;
    739 }
    740 
    741 template <>
    742 bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
    743                                             const spv_opcode_desc) {
    744   auto resultTypeIndex = 1;
    745   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    746   if (!resultType || SpvOpTypeSampler != resultType->opcode()) {
    747     DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
    748                           << inst->words[resultTypeIndex]
    749                           << "' is not a sampler type.";
    750     return false;
    751   }
    752   return true;
    753 }
    754 
    755 // True if instruction defines a type that can have a null value, as defined by
    756 // the SPIR-V spec.  Tracks composite-type components through module to check
    757 // nullability transitively.
    758 bool IsTypeNullable(const vector<uint32_t>& instruction,
    759                     const ValidationState_t& module) {
    760   uint16_t opcode;
    761   uint16_t word_count;
    762   spvOpcodeSplit(instruction[0], &word_count, &opcode);
    763   switch (static_cast<SpvOp>(opcode)) {
    764     case SpvOpTypeBool:
    765     case SpvOpTypeInt:
    766     case SpvOpTypeFloat:
    767     case SpvOpTypePointer:
    768     case SpvOpTypeEvent:
    769     case SpvOpTypeDeviceEvent:
    770     case SpvOpTypeReserveId:
    771     case SpvOpTypeQueue:
    772       return true;
    773     case SpvOpTypeArray:
    774     case SpvOpTypeMatrix:
    775     case SpvOpTypeVector: {
    776       auto base_type = module.FindDef(instruction[2]);
    777       return base_type && IsTypeNullable(base_type->words(), module);
    778     }
    779     case SpvOpTypeStruct: {
    780       for (size_t elementIndex = 2; elementIndex < instruction.size();
    781            ++elementIndex) {
    782         auto element = module.FindDef(instruction[elementIndex]);
    783         if (!element || !IsTypeNullable(element->words(), module)) return false;
    784       }
    785       return true;
    786     }
    787     default:
    788       return false;
    789   }
    790 }
    791 
    792 template <>
    793 bool idUsage::isValid<SpvOpConstantNull>(const spv_instruction_t* inst,
    794                                          const spv_opcode_desc) {
    795   auto resultTypeIndex = 1;
    796   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    797   if (!resultType || !IsTypeNullable(resultType->words(), module_)) {
    798     DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
    799                           << inst->words[resultTypeIndex]
    800                           << "' cannot have a null value.";
    801     return false;
    802   }
    803   return true;
    804 }
    805 
    806 template <>
    807 bool idUsage::isValid<SpvOpSpecConstantTrue>(const spv_instruction_t* inst,
    808                                              const spv_opcode_desc) {
    809   auto resultTypeIndex = 1;
    810   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    811   if (!resultType || SpvOpTypeBool != resultType->opcode()) {
    812     DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
    813                           << inst->words[resultTypeIndex]
    814                           << "' is not a boolean type.";
    815     return false;
    816   }
    817   return true;
    818 }
    819 
    820 template <>
    821 bool idUsage::isValid<SpvOpSpecConstantFalse>(const spv_instruction_t* inst,
    822                                               const spv_opcode_desc) {
    823   auto resultTypeIndex = 1;
    824   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    825   if (!resultType || SpvOpTypeBool != resultType->opcode()) {
    826     DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
    827                           << inst->words[resultTypeIndex]
    828                           << "' is not a boolean type.";
    829     return false;
    830   }
    831   return true;
    832 }
    833 
    834 template <>
    835 bool idUsage::isValid<SpvOpSampledImage>(const spv_instruction_t* inst,
    836                                          const spv_opcode_desc) {
    837   auto resultTypeIndex = 2;
    838   auto resultID = inst->words[resultTypeIndex];
    839   auto sampledImageInstr = module_.FindDef(resultID);
    840   // We need to validate 2 things:
    841   // * All OpSampledImage instructions must be in the same block in which their
    842   // Result <id> are consumed.
    843   // * Result <id> from OpSampledImage instructions must not appear as operands
    844   // to OpPhi instructions or OpSelect instructions, or any instructions other
    845   // than the image lookup and query instructions specified to take an operand
    846   // whose type is OpTypeSampledImage.
    847   std::vector<uint32_t> consumers = module_.getSampledImageConsumers(resultID);
    848   if (!consumers.empty()) {
    849     for (auto consumer_id : consumers) {
    850       auto consumer_instr = module_.FindDef(consumer_id);
    851       auto consumer_opcode = consumer_instr->opcode();
    852       if (consumer_instr->block() != sampledImageInstr->block()) {
    853         DIAG(resultTypeIndex)
    854             << "All OpSampledImage instructions must be in the same block in "
    855                "which their Result <id> are consumed. OpSampledImage Result "
    856                "Type <id> '"
    857             << resultID << "' has a consumer in a different basic "
    858                            "block. The consumer instruction <id> is '"
    859             << consumer_id << "'.";
    860         return false;
    861       }
    862       // TODO: The following check is incomplete. We should also check that the
    863       // Sampled Image is not used by instructions that should not take
    864       // SampledImage as an argument. We could find the list of valid
    865       // instructions by scanning for "Sampled Image" in the operand description
    866       // field in the grammar file.
    867       if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) {
    868         DIAG(resultTypeIndex)
    869             << "Result <id> from OpSampledImage instruction must not appear as "
    870                "operands of Op"
    871             << spvOpcodeString(static_cast<SpvOp>(consumer_opcode)) << "."
    872             << " Found result <id> '" << resultID << "' as an operand of <id> '"
    873             << consumer_id << "'.";
    874         return false;
    875       }
    876     }
    877   }
    878   return true;
    879 }
    880 
    881 template <>
    882 bool idUsage::isValid<SpvOpSpecConstantComposite>(const spv_instruction_t* inst,
    883                                                   const spv_opcode_desc) {
    884   // The result type must be a composite type.
    885   auto resultTypeIndex = 1;
    886   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
    887   if (!resultType || !spvOpcodeIsComposite(resultType->opcode())) {
    888     DIAG(resultTypeIndex) << "OpSpecConstantComposite Result Type <id> '"
    889                           << inst->words[resultTypeIndex]
    890                           << "' is not a composite type.";
    891     return false;
    892   }
    893   // Validation checks differ based on the type of composite type.
    894   auto constituentCount = inst->words.size() - 3;
    895   switch (resultType->opcode()) {
    896     // For Vectors, the following must be met:
    897     // * Number of constituents in the result type and the vector must match.
    898     // * All the components of the vector must have the same type (or specialize
    899     // to the same type). OpConstant and OpSpecConstant are allowed.
    900     // To check that condition, we check each supplied value argument's type
    901     // against the element type of the result type.
    902     case SpvOpTypeVector: {
    903       auto componentCount = resultType->words()[3];
    904       if (componentCount != constituentCount) {
    905         DIAG(inst->words.size() - 1)
    906             << "OpSpecConstantComposite Constituent <id> count does not match "
    907                "Result Type <id> '"
    908             << resultType->id() << "'s vector component count.";
    909         return false;
    910       }
    911       auto componentType = module_.FindDef(resultType->words()[2]);
    912       assert(componentType);
    913       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    914            constituentIndex++) {
    915         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    916         if (!constituent ||
    917             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
    918           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
    919                                  << inst->words[constituentIndex]
    920                                  << "' is not a constant or undef.";
    921           return false;
    922         }
    923         auto constituentResultType = module_.FindDef(constituent->type_id());
    924         if (!constituentResultType ||
    925             componentType->opcode() != constituentResultType->opcode()) {
    926           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
    927                                  << inst->words[constituentIndex]
    928                                  << "'s type does not match Result Type <id> '"
    929                                  << resultType->id()
    930                                  << "'s vector element type.";
    931           return false;
    932         }
    933       }
    934       break;
    935     }
    936     case SpvOpTypeMatrix: {
    937       auto columnCount = resultType->words()[3];
    938       if (columnCount != constituentCount) {
    939         DIAG(inst->words.size() - 1)
    940             << "OpSpecConstantComposite Constituent <id> count does not match "
    941                "Result Type <id> '"
    942             << resultType->id() << "'s matrix column count.";
    943         return false;
    944       }
    945 
    946       auto columnType = module_.FindDef(resultType->words()[2]);
    947       assert(columnType);
    948       auto componentCount = columnType->words()[3];
    949       auto componentType = module_.FindDef(columnType->words()[2]);
    950       assert(componentType);
    951 
    952       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    953            constituentIndex++) {
    954         auto constituent = module_.FindDef(inst->words[constituentIndex]);
    955         auto constituentOpCode = constituent->opcode();
    956         if (!constituent ||
    957             !(SpvOpSpecConstantComposite == constituentOpCode ||
    958               SpvOpConstantComposite == constituentOpCode ||
    959               SpvOpUndef == constituentOpCode)) {
    960           // The message says "... or undef" because the spec does not say
    961           // undef is a constant.
    962           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
    963                                  << inst->words[constituentIndex]
    964                                  << "' is not a constant composite or undef.";
    965           return false;
    966         }
    967         auto vector = module_.FindDef(constituent->type_id());
    968         assert(vector);
    969         if (columnType->opcode() != vector->opcode()) {
    970           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
    971                                  << inst->words[constituentIndex]
    972                                  << "' type does not match Result Type <id> '"
    973                                  << resultType->id()
    974                                  << "'s matrix column type.";
    975           return false;
    976         }
    977         auto vectorComponentType = module_.FindDef(vector->words()[2]);
    978         assert(vectorComponentType);
    979         if (componentType->id() != vectorComponentType->id()) {
    980           DIAG(constituentIndex)
    981               << "OpSpecConstantComposite Constituent <id> '"
    982               << inst->words[constituentIndex]
    983               << "' component type does not match Result Type <id> '"
    984               << resultType->id() << "'s matrix column component type.";
    985           return false;
    986         }
    987         if (componentCount != vector->words()[3]) {
    988           DIAG(constituentIndex)
    989               << "OpSpecConstantComposite Constituent <id> '"
    990               << inst->words[constituentIndex]
    991               << "' vector component count does not match Result Type <id> '"
    992               << resultType->id() << "'s vector component count.";
    993           return false;
    994         }
    995       }
    996       break;
    997     }
    998     case SpvOpTypeArray: {
    999       auto elementType = module_.FindDef(resultType->words()[2]);
   1000       assert(elementType);
   1001       auto length = module_.FindDef(resultType->words()[3]);
   1002       assert(length);
   1003       if (length->words()[3] != constituentCount) {
   1004         DIAG(inst->words.size() - 1)
   1005             << "OpSpecConstantComposite Constituent count does not match "
   1006                "Result Type <id> '"
   1007             << resultType->id() << "'s array length.";
   1008         return false;
   1009       }
   1010       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
   1011            constituentIndex++) {
   1012         auto constituent = module_.FindDef(inst->words[constituentIndex]);
   1013         if (!constituent ||
   1014             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
   1015           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
   1016                                  << inst->words[constituentIndex]
   1017                                  << "' is not a constant or undef.";
   1018           return false;
   1019         }
   1020         auto constituentType = module_.FindDef(constituent->type_id());
   1021         assert(constituentType);
   1022         if (elementType->id() != constituentType->id()) {
   1023           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
   1024                                  << inst->words[constituentIndex]
   1025                                  << "'s type does not match Result Type <id> '"
   1026                                  << resultType->id()
   1027                                  << "'s array element type.";
   1028           return false;
   1029         }
   1030       }
   1031       break;
   1032     }
   1033     case SpvOpTypeStruct: {
   1034       auto memberCount = resultType->words().size() - 2;
   1035       if (memberCount != constituentCount) {
   1036         DIAG(resultTypeIndex) << "OpSpecConstantComposite Constituent <id> '"
   1037                               << inst->words[resultTypeIndex]
   1038                               << "' count does not match Result Type <id> '"
   1039                               << resultType->id() << "'s struct member count.";
   1040         return false;
   1041       }
   1042       for (uint32_t constituentIndex = 3, memberIndex = 2;
   1043            constituentIndex < inst->words.size();
   1044            constituentIndex++, memberIndex++) {
   1045         auto constituent = module_.FindDef(inst->words[constituentIndex]);
   1046         if (!constituent ||
   1047             !spvOpcodeIsConstantOrUndef(constituent->opcode())) {
   1048           DIAG(constituentIndex) << "OpSpecConstantComposite Constituent <id> '"
   1049                                  << inst->words[constituentIndex]
   1050                                  << "' is not a constant or undef.";
   1051           return false;
   1052         }
   1053         auto constituentType = module_.FindDef(constituent->type_id());
   1054         assert(constituentType);
   1055 
   1056         auto memberType = module_.FindDef(resultType->words()[memberIndex]);
   1057         assert(memberType);
   1058         if (memberType->id() != constituentType->id()) {
   1059           DIAG(constituentIndex)
   1060               << "OpSpecConstantComposite Constituent <id> '"
   1061               << inst->words[constituentIndex]
   1062               << "' type does not match the Result Type <id> '"
   1063               << resultType->id() << "'s member type.";
   1064           return false;
   1065         }
   1066       }
   1067       break;
   1068     }
   1069     default: { assert(0 && "Unreachable!"); } break;
   1070   }
   1071   return true;
   1072 }
   1073 
   1074 #if 0
   1075 template <>
   1076 bool idUsage::isValid<SpvOpSpecConstantOp>(const spv_instruction_t *inst) {}
   1077 #endif
   1078 
   1079 template <>
   1080 bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst,
   1081                                      const spv_opcode_desc) {
   1082   auto resultTypeIndex = 1;
   1083   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
   1084   if (!resultType || SpvOpTypePointer != resultType->opcode()) {
   1085     DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
   1086                           << inst->words[resultTypeIndex]
   1087                           << "' is not a pointer type.";
   1088     return false;
   1089   }
   1090   const auto initialiserIndex = 4;
   1091   if (initialiserIndex < inst->words.size()) {
   1092     const auto initialiser = module_.FindDef(inst->words[initialiserIndex]);
   1093     const auto storageClassIndex = 3;
   1094     const auto is_module_scope_var =
   1095         initialiser && (initialiser->opcode() == SpvOpVariable) &&
   1096         (initialiser->word(storageClassIndex) != SpvStorageClassFunction);
   1097     const auto is_constant =
   1098         initialiser && spvOpcodeIsConstant(initialiser->opcode());
   1099     if (!initialiser || !(is_constant || is_module_scope_var)) {
   1100       DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
   1101                              << inst->words[initialiserIndex]
   1102                              << "' is not a constant or module-scope variable.";
   1103       return false;
   1104     }
   1105   }
   1106   return true;
   1107 }
   1108 
   1109 template <>
   1110 bool idUsage::isValid<SpvOpLoad>(const spv_instruction_t* inst,
   1111                                  const spv_opcode_desc) {
   1112   auto resultTypeIndex = 1;
   1113   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
   1114   if (!resultType) {
   1115     DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
   1116                           << inst->words[resultTypeIndex] << "' is not defind.";
   1117     return false;
   1118   }
   1119   const bool uses_variable_pointer =
   1120       module_.features().variable_pointers ||
   1121       module_.features().variable_pointers_storage_buffer;
   1122   auto pointerIndex = 3;
   1123   auto pointer = module_.FindDef(inst->words[pointerIndex]);
   1124   if (!pointer ||
   1125       (addressingModel == SpvAddressingModelLogical &&
   1126        ((!uses_variable_pointer &&
   1127          !spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
   1128         (uses_variable_pointer &&
   1129          !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
   1130     DIAG(pointerIndex) << "OpLoad Pointer <id> '" << inst->words[pointerIndex]
   1131                        << "' is not a logical pointer.";
   1132     return false;
   1133   }
   1134   auto pointerType = module_.FindDef(pointer->type_id());
   1135   if (!pointerType || pointerType->opcode() != SpvOpTypePointer) {
   1136     DIAG(pointerIndex) << "OpLoad type for pointer <id> '"
   1137                        << inst->words[pointerIndex]
   1138                        << "' is not a pointer type.";
   1139     return false;
   1140   }
   1141   auto pointeeType = module_.FindDef(pointerType->words()[3]);
   1142   if (!pointeeType || resultType->id() != pointeeType->id()) {
   1143     DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
   1144                           << inst->words[resultTypeIndex]
   1145                           << "' does not match Pointer <id> '" << pointer->id()
   1146                           << "'s type.";
   1147     return false;
   1148   }
   1149   return true;
   1150 }
   1151 
   1152 template <>
   1153 bool idUsage::isValid<SpvOpStore>(const spv_instruction_t* inst,
   1154                                   const spv_opcode_desc) {
   1155   const bool uses_variable_pointer =
   1156       module_.features().variable_pointers ||
   1157       module_.features().variable_pointers_storage_buffer;
   1158   const auto pointerIndex = 1;
   1159   auto pointer = module_.FindDef(inst->words[pointerIndex]);
   1160   if (!pointer ||
   1161       (addressingModel == SpvAddressingModelLogical &&
   1162        ((!uses_variable_pointer &&
   1163          !spvOpcodeReturnsLogicalPointer(pointer->opcode())) ||
   1164         (uses_variable_pointer &&
   1165          !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) {
   1166     DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
   1167                        << "' is not a logical pointer.";
   1168     return false;
   1169   }
   1170   auto pointerType = module_.FindDef(pointer->type_id());
   1171   if (!pointer || pointerType->opcode() != SpvOpTypePointer) {
   1172     DIAG(pointerIndex) << "OpStore type for pointer <id> '"
   1173                        << inst->words[pointerIndex]
   1174                        << "' is not a pointer type.";
   1175     return false;
   1176   }
   1177   auto type = module_.FindDef(pointerType->words()[3]);
   1178   assert(type);
   1179   if (SpvOpTypeVoid == type->opcode()) {
   1180     DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
   1181                        << "'s type is void.";
   1182     return false;
   1183   }
   1184 
   1185   auto objectIndex = 2;
   1186   auto object = module_.FindDef(inst->words[objectIndex]);
   1187   if (!object || !object->type_id()) {
   1188     DIAG(objectIndex) << "OpStore Object <id> '" << inst->words[objectIndex]
   1189                       << "' is not an object.";
   1190     return false;
   1191   }
   1192   auto objectType = module_.FindDef(object->type_id());
   1193   assert(objectType);
   1194   if (SpvOpTypeVoid == objectType->opcode()) {
   1195     DIAG(objectIndex) << "OpStore Object <id> '" << inst->words[objectIndex]
   1196                       << "'s type is void.";
   1197     return false;
   1198   }
   1199 
   1200   if (type->id() != objectType->id()) {
   1201     DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
   1202                        << "'s type does not match Object <id> '"
   1203                        << objectType->id() << "'s type.";
   1204     return false;
   1205   }
   1206   return true;
   1207 }
   1208 
   1209 template <>
   1210 bool idUsage::isValid<SpvOpCopyMemory>(const spv_instruction_t* inst,
   1211                                        const spv_opcode_desc) {
   1212   auto targetIndex = 1;
   1213   auto target = module_.FindDef(inst->words[targetIndex]);
   1214   if (!target) return false;
   1215   auto sourceIndex = 2;
   1216   auto source = module_.FindDef(inst->words[sourceIndex]);
   1217   if (!source) return false;
   1218   auto targetPointerType = module_.FindDef(target->type_id());
   1219   assert(targetPointerType);
   1220   auto targetType = module_.FindDef(targetPointerType->words()[3]);
   1221   assert(targetType);
   1222   auto sourcePointerType = module_.FindDef(source->type_id());
   1223   assert(sourcePointerType);
   1224   auto sourceType = module_.FindDef(sourcePointerType->words()[3]);
   1225   assert(sourceType);
   1226   if (targetType->id() != sourceType->id()) {
   1227     DIAG(sourceIndex) << "OpCopyMemory Target <id> '"
   1228                       << inst->words[sourceIndex]
   1229                       << "'s type does not match Source <id> '"
   1230                       << sourceType->id() << "'s type.";
   1231     return false;
   1232   }
   1233   return true;
   1234 }
   1235 
   1236 template <>
   1237 bool idUsage::isValid<SpvOpCopyMemorySized>(const spv_instruction_t* inst,
   1238                                             const spv_opcode_desc) {
   1239   auto targetIndex = 1;
   1240   auto target = module_.FindDef(inst->words[targetIndex]);
   1241   if (!target) return false;
   1242   auto sourceIndex = 2;
   1243   auto source = module_.FindDef(inst->words[sourceIndex]);
   1244   if (!source) return false;
   1245   auto sizeIndex = 3;
   1246   auto size = module_.FindDef(inst->words[sizeIndex]);
   1247   if (!size) return false;
   1248   auto targetPointerType = module_.FindDef(target->type_id());
   1249   if (!targetPointerType || SpvOpTypePointer != targetPointerType->opcode()) {
   1250     DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
   1251                       << inst->words[targetIndex] << "' is not a pointer.";
   1252     return false;
   1253   }
   1254   auto sourcePointerType = module_.FindDef(source->type_id());
   1255   if (!sourcePointerType || SpvOpTypePointer != sourcePointerType->opcode()) {
   1256     DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
   1257                       << inst->words[sourceIndex] << "' is not a pointer.";
   1258     return false;
   1259   }
   1260   switch (size->opcode()) {
   1261     // TODO: The following opcode's are assumed to be valid, refer to the
   1262     // following bug https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13871 for
   1263     // clarification
   1264     case SpvOpConstant:
   1265     case SpvOpSpecConstant: {
   1266       auto sizeType = module_.FindDef(size->type_id());
   1267       assert(sizeType);
   1268       if (SpvOpTypeInt != sizeType->opcode()) {
   1269         DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
   1270                         << inst->words[sizeIndex]
   1271                         << "'s type is not an integer type.";
   1272         return false;
   1273       }
   1274     } break;
   1275     case SpvOpVariable: {
   1276       auto pointerType = module_.FindDef(size->type_id());
   1277       assert(pointerType);
   1278       auto sizeType = module_.FindDef(pointerType->type_id());
   1279       if (!sizeType || SpvOpTypeInt != sizeType->opcode()) {
   1280         DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
   1281                         << inst->words[sizeIndex]
   1282                         << "'s variable type is not an integer type.";
   1283         return false;
   1284       }
   1285     } break;
   1286     default:
   1287       DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
   1288                       << inst->words[sizeIndex]
   1289                       << "' is not a constant or variable.";
   1290       return false;
   1291   }
   1292   // TODO: Check that consant is a least size 1, see the same bug as above for
   1293   // clarification?
   1294   return true;
   1295 }
   1296 
   1297 template <>
   1298 bool idUsage::isValid<SpvOpAccessChain>(const spv_instruction_t* inst,
   1299                                         const spv_opcode_desc) {
   1300   std::string instr_name =
   1301       "Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
   1302 
   1303   // The result type must be OpTypePointer. Result Type is at word 1.
   1304   auto resultTypeIndex = 1;
   1305   auto resultTypeInstr = module_.FindDef(inst->words[resultTypeIndex]);
   1306   if (SpvOpTypePointer != resultTypeInstr->opcode()) {
   1307     DIAG(resultTypeIndex) << "The Result Type of " << instr_name << " <id> '"
   1308                           << inst->words[2]
   1309                           << "' must be OpTypePointer. Found Op"
   1310                           << spvOpcodeString(
   1311                                  static_cast<SpvOp>(resultTypeInstr->opcode()))
   1312                           << ".";
   1313     return false;
   1314   }
   1315 
   1316   // Result type is a pointer. Find out what it's pointing to.
   1317   // This will be used to make sure the indexing results in the same type.
   1318   // OpTypePointer word 3 is the type being pointed to.
   1319   auto resultTypePointedTo = module_.FindDef(resultTypeInstr->word(3));
   1320 
   1321   // Base must be a pointer, pointing to the base of a composite object.
   1322   auto baseIdIndex = 3;
   1323   auto baseInstr = module_.FindDef(inst->words[baseIdIndex]);
   1324   auto baseTypeInstr = module_.FindDef(baseInstr->type_id());
   1325   if (!baseTypeInstr || SpvOpTypePointer != baseTypeInstr->opcode()) {
   1326     DIAG(baseIdIndex) << "The Base <id> '" << inst->words[baseIdIndex]
   1327                       << "' in " << instr_name
   1328                       << " instruction must be a pointer.";
   1329     return false;
   1330   }
   1331 
   1332   // The result pointer storage class and base pointer storage class must match.
   1333   // Word 2 of OpTypePointer is the Storage Class.
   1334   auto resultTypeStorageClass = resultTypeInstr->word(2);
   1335   auto baseTypeStorageClass = baseTypeInstr->word(2);
   1336   if (resultTypeStorageClass != baseTypeStorageClass) {
   1337     DIAG(resultTypeIndex) << "The result pointer storage class and base "
   1338                              "pointer storage class in "
   1339                           << instr_name << " do not match.";
   1340     return false;
   1341   }
   1342 
   1343   // The type pointed to by OpTypePointer (word 3) must be a composite type.
   1344   auto typePointedTo = module_.FindDef(baseTypeInstr->word(3));
   1345 
   1346   // Check Universal Limit (SPIR-V Spec. Section 2.17).
   1347   // The number of indexes passed to OpAccessChain may not exceed 255
   1348   // The instruction includes 4 words + N words (for N indexes)
   1349   const size_t num_indexes = inst->words.size() - 4;
   1350   const size_t num_indexes_limit =
   1351       module_.options()->universal_limits_.max_access_chain_indexes;
   1352   if (num_indexes > num_indexes_limit) {
   1353     DIAG(resultTypeIndex) << "The number of indexes in " << instr_name
   1354                           << " may not exceed " << num_indexes_limit
   1355                           << ". Found " << num_indexes << " indexes.";
   1356     return false;
   1357   }
   1358   // Indexes walk the type hierarchy to the desired depth, potentially down to
   1359   // scalar granularity. The first index in Indexes will select the top-level
   1360   // member/element/component/element of the base composite. All composite
   1361   // constituents use zero-based numbering, as described by their OpType...
   1362   // instruction. The second index will apply similarly to that result, and so
   1363   // on. Once any non-composite type is reached, there must be no remaining
   1364   // (unused) indexes.
   1365   for (size_t i = 4; i < inst->words.size(); ++i) {
   1366     const uint32_t cur_word = inst->words[i];
   1367     // Earlier ID checks ensure that cur_word definition exists.
   1368     auto cur_word_instr = module_.FindDef(cur_word);
   1369     // The index must be a scalar integer type (See OpAccessChain in the Spec.)
   1370     auto indexTypeInstr = module_.FindDef(cur_word_instr->type_id());
   1371     if (!indexTypeInstr || SpvOpTypeInt != indexTypeInstr->opcode()) {
   1372       DIAG(i) << "Indexes passed to " << instr_name
   1373               << " must be of type integer.";
   1374       return false;
   1375     }
   1376     switch (typePointedTo->opcode()) {
   1377       case SpvOpTypeMatrix:
   1378       case SpvOpTypeVector:
   1379       case SpvOpTypeArray:
   1380       case SpvOpTypeRuntimeArray: {
   1381         // In OpTypeMatrix, OpTypeVector, OpTypeArray, and OpTypeRuntimeArray,
   1382         // word 2 is the Element Type.
   1383         typePointedTo = module_.FindDef(typePointedTo->word(2));
   1384         break;
   1385       }
   1386       case SpvOpTypeStruct: {
   1387         // In case of structures, there is an additional constraint on the
   1388         // index: the index must be an OpConstant.
   1389         if (SpvOpConstant != cur_word_instr->opcode()) {
   1390           DIAG(i) << "The <id> passed to " << instr_name
   1391                   << " to index into a "
   1392                      "structure must be an OpConstant.";
   1393           return false;
   1394         }
   1395         // Get the index value from the OpConstant (word 3 of OpConstant).
   1396         // OpConstant could be a signed integer. But it's okay to treat it as
   1397         // unsigned because a negative constant int would never be seen as
   1398         // correct as a struct offset, since structs can't have more than 2
   1399         // billion members.
   1400         const uint32_t cur_index = cur_word_instr->word(3);
   1401         // The index points to the struct member we want, therefore, the index
   1402         // should be less than the number of struct members.
   1403         const uint32_t num_struct_members =
   1404             static_cast<uint32_t>(typePointedTo->words().size() - 2);
   1405         if (cur_index >= num_struct_members) {
   1406           DIAG(i) << "Index is out of bounds: " << instr_name
   1407                   << " can not find index " << cur_index
   1408                   << " into the structure <id> '" << typePointedTo->id()
   1409                   << "'. This structure has " << num_struct_members
   1410                   << " members. Largest valid index is "
   1411                   << num_struct_members - 1 << ".";
   1412           return false;
   1413         }
   1414         // Struct members IDs start at word 2 of OpTypeStruct.
   1415         auto structMemberId = typePointedTo->word(cur_index + 2);
   1416         typePointedTo = module_.FindDef(structMemberId);
   1417         break;
   1418       }
   1419       default: {
   1420         // Give an error. reached non-composite type while indexes still remain.
   1421         DIAG(i) << instr_name << " reached non-composite type while indexes "
   1422                                  "still remain to be traversed.";
   1423         return false;
   1424       }
   1425     }
   1426   }
   1427   // At this point, we have fully walked down from the base using the indeces.
   1428   // The type being pointed to should be the same as the result type.
   1429   if (typePointedTo->id() != resultTypePointedTo->id()) {
   1430     DIAG(resultTypeIndex)
   1431         << instr_name << " result type (Op"
   1432         << spvOpcodeString(static_cast<SpvOp>(resultTypePointedTo->opcode()))
   1433         << ") does not match the type that results from indexing into the base "
   1434            "<id> (Op"
   1435         << spvOpcodeString(static_cast<SpvOp>(typePointedTo->opcode())) << ").";
   1436     return false;
   1437   }
   1438 
   1439   return true;
   1440 }
   1441 
   1442 template <>
   1443 bool idUsage::isValid<SpvOpInBoundsAccessChain>(
   1444     const spv_instruction_t* inst, const spv_opcode_desc opcodeEntry) {
   1445   return isValid<SpvOpAccessChain>(inst, opcodeEntry);
   1446 }
   1447 
   1448 template <>
   1449 bool idUsage::isValid<SpvOpPtrAccessChain>(const spv_instruction_t* inst,
   1450                                            const spv_opcode_desc opcodeEntry) {
   1451   // OpPtrAccessChain's validation rules are similar to OpAccessChain, with one
   1452   // difference: word 4 must be id of an integer (Element <id>).
   1453   // The grammar guarantees that there are at least 5 words in the instruction
   1454   // (i.e. if there are fewer than 5 words, the SPIR-V code will not compile.)
   1455   int elem_index = 4;
   1456   // We can remove the Element <id> from the instruction words, and simply call
   1457   // the validation code of OpAccessChain.
   1458   spv_instruction_t new_inst = *inst;
   1459   new_inst.words.erase(new_inst.words.begin() + elem_index);
   1460   return isValid<SpvOpAccessChain>(&new_inst, opcodeEntry);
   1461 }
   1462 
   1463 template <>
   1464 bool idUsage::isValid<SpvOpInBoundsPtrAccessChain>(
   1465     const spv_instruction_t* inst, const spv_opcode_desc opcodeEntry) {
   1466   // Has the same validation rules as OpPtrAccessChain
   1467   return isValid<SpvOpPtrAccessChain>(inst, opcodeEntry);
   1468 }
   1469 
   1470 #if 0
   1471 template <>
   1472 bool idUsage::isValid<SpvOpArrayLength>(const spv_instruction_t *inst,
   1473                                         const spv_opcode_desc opcodeEntry) {}
   1474 #endif
   1475 
   1476 #if 0
   1477 template <>
   1478 bool idUsage::isValid<SpvOpImagePointer>(const spv_instruction_t *inst,
   1479                                          const spv_opcode_desc opcodeEntry) {}
   1480 #endif
   1481 
   1482 #if 0
   1483 template <>
   1484 bool idUsage::isValid<SpvOpGenericPtrMemSemantics>(
   1485     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1486 #endif
   1487 
   1488 template <>
   1489 bool idUsage::isValid<SpvOpFunction>(const spv_instruction_t* inst,
   1490                                      const spv_opcode_desc) {
   1491   auto resultTypeIndex = 1;
   1492   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
   1493   if (!resultType) return false;
   1494   auto functionTypeIndex = 4;
   1495   auto functionType = module_.FindDef(inst->words[functionTypeIndex]);
   1496   if (!functionType || SpvOpTypeFunction != functionType->opcode()) {
   1497     DIAG(functionTypeIndex) << "OpFunction Function Type <id> '"
   1498                             << inst->words[functionTypeIndex]
   1499                             << "' is not a function type.";
   1500     return false;
   1501   }
   1502   auto returnType = module_.FindDef(functionType->words()[2]);
   1503   assert(returnType);
   1504   if (returnType->id() != resultType->id()) {
   1505     DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
   1506                           << inst->words[resultTypeIndex]
   1507                           << "' does not match the Function Type <id> '"
   1508                           << resultType->id() << "'s return type.";
   1509     return false;
   1510   }
   1511   return true;
   1512 }
   1513 
   1514 template <>
   1515 bool idUsage::isValid<SpvOpFunctionParameter>(const spv_instruction_t* inst,
   1516                                               const spv_opcode_desc) {
   1517   auto resultTypeIndex = 1;
   1518   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
   1519   if (!resultType) return false;
   1520   // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
   1521   size_t paramIndex = 0;
   1522   assert(firstInst < inst && "Invalid instruction pointer");
   1523   while (firstInst != --inst) {
   1524     if (SpvOpFunction == inst->opcode) {
   1525       break;
   1526     } else if (SpvOpFunctionParameter == inst->opcode) {
   1527       paramIndex++;
   1528     }
   1529   }
   1530   auto functionType = module_.FindDef(inst->words[4]);
   1531   assert(functionType);
   1532   if (paramIndex >= functionType->words().size() - 3) {
   1533     DIAG(0) << "Too many OpFunctionParameters for " << inst->words[2]
   1534             << ": expected " << functionType->words().size() - 3
   1535             << " based on the function's type";
   1536     return false;
   1537   }
   1538   auto paramType = module_.FindDef(functionType->words()[paramIndex + 3]);
   1539   assert(paramType);
   1540   if (resultType->id() != paramType->id()) {
   1541     DIAG(resultTypeIndex) << "OpFunctionParameter Result Type <id> '"
   1542                           << inst->words[resultTypeIndex]
   1543                           << "' does not match the OpTypeFunction parameter "
   1544                              "type of the same index.";
   1545     return false;
   1546   }
   1547   return true;
   1548 }
   1549 
   1550 template <>
   1551 bool idUsage::isValid<SpvOpFunctionCall>(const spv_instruction_t* inst,
   1552                                          const spv_opcode_desc) {
   1553   auto resultTypeIndex = 1;
   1554   auto resultType = module_.FindDef(inst->words[resultTypeIndex]);
   1555   if (!resultType) return false;
   1556   auto functionIndex = 3;
   1557   auto function = module_.FindDef(inst->words[functionIndex]);
   1558   if (!function || SpvOpFunction != function->opcode()) {
   1559     DIAG(functionIndex) << "OpFunctionCall Function <id> '"
   1560                         << inst->words[functionIndex] << "' is not a function.";
   1561     return false;
   1562   }
   1563   auto returnType = module_.FindDef(function->type_id());
   1564   assert(returnType);
   1565   if (returnType->id() != resultType->id()) {
   1566     DIAG(resultTypeIndex) << "OpFunctionCall Result Type <id> '"
   1567                           << inst->words[resultTypeIndex]
   1568                           << "'s type does not match Function <id> '"
   1569                           << returnType->id() << "'s return type.";
   1570     return false;
   1571   }
   1572   auto functionType = module_.FindDef(function->words()[4]);
   1573   assert(functionType);
   1574   auto functionCallArgCount = inst->words.size() - 4;
   1575   auto functionParamCount = functionType->words().size() - 3;
   1576   if (functionParamCount != functionCallArgCount) {
   1577     DIAG(inst->words.size() - 1)
   1578         << "OpFunctionCall Function <id>'s parameter count does not match "
   1579            "the argument count.";
   1580     return false;
   1581   }
   1582   for (size_t argumentIndex = 4, paramIndex = 3;
   1583        argumentIndex < inst->words.size(); argumentIndex++, paramIndex++) {
   1584     auto argument = module_.FindDef(inst->words[argumentIndex]);
   1585     if (!argument) return false;
   1586     auto argumentType = module_.FindDef(argument->type_id());
   1587     assert(argumentType);
   1588     auto parameterType = module_.FindDef(functionType->words()[paramIndex]);
   1589     assert(parameterType);
   1590     if (argumentType->id() != parameterType->id()) {
   1591       DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
   1592                           << inst->words[argumentIndex]
   1593                           << "'s type does not match Function <id> '"
   1594                           << parameterType->id() << "'s parameter type.";
   1595       return false;
   1596     }
   1597   }
   1598   return true;
   1599 }
   1600 
   1601 #if 0
   1602 template <>
   1603 bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
   1604                                      const spv_opcode_desc opcodeEntry) {}
   1605 #endif
   1606 
   1607 #if 0
   1608 template <>
   1609 bool idUsage::isValid<OpConvertFToS>(const spv_instruction_t *inst,
   1610                                      const spv_opcode_desc opcodeEntry) {}
   1611 #endif
   1612 
   1613 #if 0
   1614 template <>
   1615 bool idUsage::isValid<OpConvertSToF>(const spv_instruction_t *inst,
   1616                                      const spv_opcode_desc opcodeEntry) {}
   1617 #endif
   1618 
   1619 #if 0
   1620 template <>
   1621 bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
   1622                                      const spv_opcode_desc opcodeEntry) {}
   1623 #endif
   1624 
   1625 #if 0
   1626 template <>
   1627 bool idUsage::isValid<OpUConvert>(const spv_instruction_t *inst,
   1628                                   const spv_opcode_desc opcodeEntry) {}
   1629 #endif
   1630 
   1631 #if 0
   1632 template <>
   1633 bool idUsage::isValid<OpSConvert>(const spv_instruction_t *inst,
   1634                                   const spv_opcode_desc opcodeEntry) {}
   1635 #endif
   1636 
   1637 #if 0
   1638 template <>
   1639 bool idUsage::isValid<OpFConvert>(const spv_instruction_t *inst,
   1640                                   const spv_opcode_desc opcodeEntry) {}
   1641 #endif
   1642 
   1643 #if 0
   1644 template <>
   1645 bool idUsage::isValid<OpConvertPtrToU>(const spv_instruction_t *inst,
   1646                                        const spv_opcode_desc opcodeEntry) {
   1647 }
   1648 #endif
   1649 
   1650 #if 0
   1651 template <>
   1652 bool idUsage::isValid<OpConvertUToPtr>(const spv_instruction_t *inst,
   1653                                        const spv_opcode_desc opcodeEntry) {
   1654 }
   1655 #endif
   1656 
   1657 #if 0
   1658 template <>
   1659 bool idUsage::isValid<OpPtrCastToGeneric>(
   1660     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1661 #endif
   1662 
   1663 #if 0
   1664 template <>
   1665 bool idUsage::isValid<OpGenericCastToPtr>(
   1666     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1667 #endif
   1668 
   1669 #if 0
   1670 template <>
   1671 bool idUsage::isValid<OpBitcast>(const spv_instruction_t *inst,
   1672                                  const spv_opcode_desc opcodeEntry) {}
   1673 #endif
   1674 
   1675 #if 0
   1676 template <>
   1677 bool idUsage::isValid<OpGenericCastToPtrExplicit>(
   1678     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1679 #endif
   1680 
   1681 #if 0
   1682 template <>
   1683 bool idUsage::isValid<OpSatConvertSToU>(const spv_instruction_t *inst) {}
   1684 #endif
   1685 
   1686 #if 0
   1687 template <>
   1688 bool idUsage::isValid<OpSatConvertUToS>(const spv_instruction_t *inst) {}
   1689 #endif
   1690 
   1691 #if 0
   1692 template <>
   1693 bool idUsage::isValid<OpVectorExtractDynamic>(
   1694     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1695 #endif
   1696 
   1697 #if 0
   1698 template <>
   1699 bool idUsage::isValid<OpVectorInsertDynamic>(
   1700     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1701 #endif
   1702 
   1703 #if 0
   1704 template <>
   1705 bool idUsage::isValid<OpVectorShuffle>(const spv_instruction_t *inst,
   1706                                        const spv_opcode_desc opcodeEntry) {
   1707 }
   1708 #endif
   1709 
   1710 #if 0
   1711 template <>
   1712 bool idUsage::isValid<OpCompositeConstruct>(
   1713     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1714 #endif
   1715 
   1716 // Walks the composite type hierarchy starting from the base.
   1717 // At each step, the iterator is dereferenced to get the next literal index.
   1718 // Indexes walk the type hierarchy to the desired depth, potentially down to
   1719 // scalar granularity. The first index in Indexes will select the top-level
   1720 // member/element/component/element of the base composite. All composite
   1721 // constituents use zero-based numbering, as described by their OpType...
   1722 // instruction. The second index will apply similarly to that result, and so
   1723 // on. Once any non-composite type is reached, there must be no remaining
   1724 // (unused) indexes.
   1725 // Returns true on success and false otherwise.
   1726 // If successful, the final type reached by indexing is returned by reference.
   1727 // If an error occurs, the error string is returned by reference.
   1728 bool walkCompositeTypeHierarchy(
   1729     const ValidationState_t& module,
   1730     std::vector<uint32_t>::const_iterator word_iter,
   1731     std::vector<uint32_t>::const_iterator word_iter_end,
   1732     const libspirv::Instruction* base,
   1733     const libspirv::Instruction** result_type_instr,
   1734     std::function<std::string(void)> instr_name, std::ostream* error) {
   1735   auto cur_type = base;
   1736   for (; word_iter != word_iter_end; ++word_iter) {
   1737     switch (cur_type->opcode()) {
   1738       case SpvOpTypeMatrix:
   1739       case SpvOpTypeVector:
   1740       case SpvOpTypeArray:
   1741       case SpvOpTypeRuntimeArray: {
   1742         // In OpTypeMatrix, OpTypeVector, OpTypeArray, and OpTypeRuntimeArray,
   1743         // word 2 is the Element Type.
   1744         cur_type = module.FindDef(cur_type->word(2));
   1745         break;
   1746       }
   1747       case SpvOpTypeStruct: {
   1748         // Get the index into the structure.
   1749         const uint32_t cur_index = *word_iter;
   1750         // The index points to the struct member we want, therefore, the index
   1751         // should be less than the number of struct members.
   1752         const uint32_t num_struct_members =
   1753             static_cast<uint32_t>(cur_type->words().size() - 2);
   1754         if (cur_index >= num_struct_members) {
   1755           *error << "Index is out of bounds: " << instr_name()
   1756                  << " can not find index " << cur_index
   1757                  << " into the structure <id> '" << cur_type->id()
   1758                  << "'. This structure has " << num_struct_members
   1759                  << " members. Largest valid index is "
   1760                  << num_struct_members - 1 << ".";
   1761           return false;
   1762         }
   1763         // Struct members IDs start at word 2 of OpTypeStruct.
   1764         auto structMemberId = cur_type->word(cur_index + 2);
   1765         cur_type = module.FindDef(structMemberId);
   1766         break;
   1767       }
   1768       default: {
   1769         // Give an error. reached non-composite type while indexes still remain.
   1770         *error << instr_name() << " reached non-composite type while indexes "
   1771                                   "still remain to be traversed.";
   1772         return false;
   1773       }
   1774     }
   1775   }
   1776   *result_type_instr = cur_type;
   1777   return true;
   1778 }
   1779 
   1780 template <>
   1781 bool idUsage::isValid<SpvOpCompositeExtract>(const spv_instruction_t* inst,
   1782                                              const spv_opcode_desc) {
   1783   auto instr_name = [&inst]() {
   1784     std::string name =
   1785         "Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
   1786     return name;
   1787   };
   1788 
   1789   // Remember the result type. Result Type is at word 1.
   1790   // This will be used to make sure the indexing results in the same type.
   1791   const size_t resultTypeIndex = 1;
   1792   auto resultTypeInstr = module_.FindDef(inst->words[resultTypeIndex]);
   1793 
   1794   // The Composite <id> is at word 3. ID definition checks ensure this id is
   1795   // already defined.
   1796   auto baseInstr = module_.FindDef(inst->words[3]);
   1797   auto curTypeInstr = module_.FindDef(baseInstr->type_id());
   1798 
   1799   // Check Universal Limit (SPIR-V Spec. Section 2.17).
   1800   // The number of indexes passed to OpCompositeExtract may not exceed 255.
   1801   // The instruction includes 4 words + N words (for N indexes)
   1802   const size_t num_indexes = inst->words.size() - 4;
   1803   const size_t num_indexes_limit = 255;
   1804   if (num_indexes > num_indexes_limit) {
   1805     DIAG(resultTypeIndex) << "The number of indexes in " << instr_name()
   1806                           << " may not exceed " << num_indexes_limit
   1807                           << ". Found " << num_indexes << " indexes.";
   1808     return false;
   1809   }
   1810 
   1811   // Walk down the composite type structure. Indexes start at word 4.
   1812   const libspirv::Instruction* indexedTypeInstr = nullptr;
   1813   std::ostringstream error;
   1814   bool success = walkCompositeTypeHierarchy(
   1815       module_, inst->words.begin() + 4, inst->words.end(), curTypeInstr,
   1816       &indexedTypeInstr, instr_name, &error);
   1817   if (!success) {
   1818     DIAG(resultTypeIndex) << error.str();
   1819     return success;
   1820   }
   1821 
   1822   // At this point, we have fully walked down from the base using the indexes.
   1823   // The type being pointed to should be the same as the result type.
   1824   if (indexedTypeInstr->id() != resultTypeInstr->id()) {
   1825     DIAG(resultTypeIndex)
   1826         << instr_name() << " result type (Op"
   1827         << spvOpcodeString(static_cast<SpvOp>(resultTypeInstr->opcode()))
   1828         << ") does not match the type that results from indexing into the "
   1829            "composite (Op"
   1830         << spvOpcodeString(static_cast<SpvOp>(indexedTypeInstr->opcode()))
   1831         << ").";
   1832     return false;
   1833   }
   1834 
   1835   return true;
   1836 }
   1837 
   1838 template <>
   1839 bool idUsage::isValid<SpvOpCompositeInsert>(const spv_instruction_t* inst,
   1840                                             const spv_opcode_desc) {
   1841   auto instr_name = [&inst]() {
   1842     std::string name =
   1843         "Op" + std::string(spvOpcodeString(static_cast<SpvOp>(inst->opcode)));
   1844     return name;
   1845   };
   1846 
   1847   // Result Type must be the same as Composite type. Result Type <id> is the
   1848   // word at index 1. Composite is at word 4.
   1849   // The grammar guarantees that the instruction has at least 5 words.
   1850   // ID definition checks ensure these IDs are already defined.
   1851   const size_t resultTypeIndex = 1;
   1852   const size_t resultIdIndex = 2;
   1853   const size_t compositeIndex = 4;
   1854   auto resultTypeInstr = module_.FindDef(inst->words[resultTypeIndex]);
   1855   auto compositeInstr = module_.FindDef(inst->words[compositeIndex]);
   1856   auto compositeTypeInstr = module_.FindDef(compositeInstr->type_id());
   1857   if (resultTypeInstr != compositeTypeInstr) {
   1858     DIAG(resultTypeIndex)
   1859         << "The Result Type must be the same as Composite type in "
   1860         << instr_name() << " yielding Result Id " << inst->words[resultIdIndex]
   1861         << ".";
   1862     return false;
   1863   }
   1864 
   1865   // Check Universal Limit (SPIR-V Spec. Section 2.17).
   1866   // The number of indexes passed to OpCompositeInsert may not exceed 255.
   1867   // The instruction includes 5 words + N words (for N indexes)
   1868   const size_t num_indexes = inst->words.size() - 5;
   1869   const size_t num_indexes_limit = 255;
   1870   if (num_indexes > num_indexes_limit) {
   1871     DIAG(resultTypeIndex) << "The number of indexes in " << instr_name()
   1872                           << " may not exceed " << num_indexes_limit
   1873                           << ". Found " << num_indexes << " indexes.";
   1874     return false;
   1875   }
   1876 
   1877   // Walk the composite type structure. Indexes start at word 5.
   1878   const libspirv::Instruction* indexedTypeInstr = nullptr;
   1879   std::ostringstream error;
   1880   bool success = walkCompositeTypeHierarchy(
   1881       module_, inst->words.begin() + 5, inst->words.end(), compositeTypeInstr,
   1882       &indexedTypeInstr, instr_name, &error);
   1883   if (!success) {
   1884     DIAG(resultTypeIndex) << error.str();
   1885     return success;
   1886   }
   1887 
   1888   // At this point, we have fully walked down from the base using the indexes.
   1889   // The type being pointed to should be the same as the object type that is
   1890   // about to be inserted.
   1891   auto objectIdIndex = 3;
   1892   auto objectInstr = module_.FindDef(inst->words[objectIdIndex]);
   1893   auto objectTypeInstr = module_.FindDef(objectInstr->type_id());
   1894   if (indexedTypeInstr->id() != objectTypeInstr->id()) {
   1895     DIAG(objectIdIndex)
   1896         << "The Object type (Op"
   1897         << spvOpcodeString(static_cast<SpvOp>(objectTypeInstr->opcode()))
   1898         << ") in " << instr_name() << " does not match the type that results "
   1899                                       "from indexing into the Composite (Op"
   1900         << spvOpcodeString(static_cast<SpvOp>(indexedTypeInstr->opcode()))
   1901         << ").";
   1902     return false;
   1903   }
   1904 
   1905   return true;
   1906 }
   1907 
   1908 #if 0
   1909 template <>
   1910 bool idUsage::isValid<OpCopyObject>(const spv_instruction_t *inst,
   1911                                     const spv_opcode_desc opcodeEntry) {}
   1912 #endif
   1913 
   1914 #if 0
   1915 template <>
   1916 bool idUsage::isValid<OpTranspose>(const spv_instruction_t *inst,
   1917                                    const spv_opcode_desc opcodeEntry) {}
   1918 #endif
   1919 
   1920 #if 0
   1921 template <>
   1922 bool idUsage::isValid<OpSNegate>(const spv_instruction_t *inst,
   1923                                  const spv_opcode_desc opcodeEntry) {}
   1924 #endif
   1925 
   1926 #if 0
   1927 template <>
   1928 bool idUsage::isValid<OpFNegate>(const spv_instruction_t *inst,
   1929                                  const spv_opcode_desc opcodeEntry) {}
   1930 #endif
   1931 
   1932 #if 0
   1933 template <>
   1934 bool idUsage::isValid<OpNot>(const spv_instruction_t *inst,
   1935                              const spv_opcode_desc opcodeEntry) {}
   1936 #endif
   1937 
   1938 #if 0
   1939 template <>
   1940 bool idUsage::isValid<OpIAdd>(const spv_instruction_t *inst,
   1941                               const spv_opcode_desc opcodeEntry) {}
   1942 #endif
   1943 
   1944 #if 0
   1945 template <>
   1946 bool idUsage::isValid<OpFAdd>(const spv_instruction_t *inst,
   1947                               const spv_opcode_desc opcodeEntry) {}
   1948 #endif
   1949 
   1950 #if 0
   1951 template <>
   1952 bool idUsage::isValid<OpISub>(const spv_instruction_t *inst,
   1953                               const spv_opcode_desc opcodeEntry) {}
   1954 #endif
   1955 
   1956 #if 0
   1957 template <>
   1958 bool idUsage::isValid<OpFSub>(const spv_instruction_t *inst,
   1959                               const spv_opcode_desc opcodeEntry) {}
   1960 #endif
   1961 
   1962 #if 0
   1963 template <>
   1964 bool idUsage::isValid<OpIMul>(const spv_instruction_t *inst,
   1965                               const spv_opcode_desc opcodeEntry) {}
   1966 #endif
   1967 
   1968 #if 0
   1969 template <>
   1970 bool idUsage::isValid<OpFMul>(const spv_instruction_t *inst,
   1971                               const spv_opcode_desc opcodeEntry) {}
   1972 #endif
   1973 
   1974 #if 0
   1975 template <>
   1976 bool idUsage::isValid<OpUDiv>(const spv_instruction_t *inst,
   1977                               const spv_opcode_desc opcodeEntry) {}
   1978 #endif
   1979 
   1980 #if 0
   1981 template <>
   1982 bool idUsage::isValid<OpSDiv>(const spv_instruction_t *inst,
   1983                               const spv_opcode_desc opcodeEntry) {}
   1984 #endif
   1985 
   1986 #if 0
   1987 template <>
   1988 bool idUsage::isValid<OpFDiv>(const spv_instruction_t *inst,
   1989                               const spv_opcode_desc opcodeEntry) {}
   1990 #endif
   1991 
   1992 #if 0
   1993 template <>
   1994 bool idUsage::isValid<OpUMod>(const spv_instruction_t *inst,
   1995                               const spv_opcode_desc opcodeEntry) {}
   1996 #endif
   1997 
   1998 #if 0
   1999 template <>
   2000 bool idUsage::isValid<OpSRem>(const spv_instruction_t *inst,
   2001                               const spv_opcode_desc opcodeEntry) {}
   2002 #endif
   2003 
   2004 #if 0
   2005 template <>
   2006 bool idUsage::isValid<OpSMod>(const spv_instruction_t *inst,
   2007                               const spv_opcode_desc opcodeEntry) {}
   2008 #endif
   2009 
   2010 #if 0
   2011 template <>
   2012 bool idUsage::isValid<OpFRem>(const spv_instruction_t *inst,
   2013                               const spv_opcode_desc opcodeEntry) {}
   2014 #endif
   2015 
   2016 #if 0
   2017 template <>
   2018 bool idUsage::isValid<OpFMod>(const spv_instruction_t *inst,
   2019                               const spv_opcode_desc opcodeEntry) {}
   2020 #endif
   2021 
   2022 #if 0
   2023 template <>
   2024 bool idUsage::isValid<OpVectorTimesScalar>(
   2025     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2026 #endif
   2027 
   2028 #if 0
   2029 template <>
   2030 bool idUsage::isValid<OpMatrixTimesScalar>(
   2031     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2032 #endif
   2033 
   2034 #if 0
   2035 template <>
   2036 bool idUsage::isValid<OpVectorTimesMatrix>(
   2037     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2038 #endif
   2039 
   2040 #if 0
   2041 template <>
   2042 bool idUsage::isValid<OpMatrixTimesVector>(
   2043     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2044 #endif
   2045 
   2046 #if 0
   2047 template <>
   2048 bool idUsage::isValid<OpMatrixTimesMatrix>(
   2049     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2050 #endif
   2051 
   2052 #if 0
   2053 template <>
   2054 bool idUsage::isValid<OpOuterProduct>(const spv_instruction_t *inst,
   2055                                       const spv_opcode_desc opcodeEntry) {}
   2056 #endif
   2057 
   2058 #if 0
   2059 template <>
   2060 bool idUsage::isValid<OpDot>(const spv_instruction_t *inst,
   2061                              const spv_opcode_desc opcodeEntry) {}
   2062 #endif
   2063 
   2064 #if 0
   2065 template <>
   2066 bool idUsage::isValid<OpShiftRightLogical>(
   2067     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2068 #endif
   2069 
   2070 #if 0
   2071 template <>
   2072 bool idUsage::isValid<OpShiftRightArithmetic>(
   2073     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2074 #endif
   2075 
   2076 #if 0
   2077 template <>
   2078 bool idUsage::isValid<OpShiftLeftLogical>(
   2079     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2080 #endif
   2081 
   2082 #if 0
   2083 template <>
   2084 bool idUsage::isValid<OpBitwiseOr>(const spv_instruction_t *inst,
   2085                                    const spv_opcode_desc opcodeEntry) {}
   2086 #endif
   2087 
   2088 #if 0
   2089 template <>
   2090 bool idUsage::isValid<OpBitwiseXor>(const spv_instruction_t *inst,
   2091                                     const spv_opcode_desc opcodeEntry) {}
   2092 #endif
   2093 
   2094 #if 0
   2095 template <>
   2096 bool idUsage::isValid<OpBitwiseAnd>(const spv_instruction_t *inst,
   2097                                     const spv_opcode_desc opcodeEntry) {}
   2098 #endif
   2099 
   2100 #if 0
   2101 template <>
   2102 bool idUsage::isValid<OpAny>(const spv_instruction_t *inst,
   2103                              const spv_opcode_desc opcodeEntry) {}
   2104 #endif
   2105 
   2106 #if 0
   2107 template <>
   2108 bool idUsage::isValid<OpAll>(const spv_instruction_t *inst,
   2109                              const spv_opcode_desc opcodeEntry) {}
   2110 #endif
   2111 
   2112 #if 0
   2113 template <>
   2114 bool idUsage::isValid<OpIsNan>(const spv_instruction_t *inst,
   2115                                const spv_opcode_desc opcodeEntry) {}
   2116 #endif
   2117 
   2118 #if 0
   2119 template <>
   2120 bool idUsage::isValid<OpIsInf>(const spv_instruction_t *inst,
   2121                                const spv_opcode_desc opcodeEntry) {}
   2122 #endif
   2123 
   2124 #if 0
   2125 template <>
   2126 bool idUsage::isValid<OpIsFinite>(const spv_instruction_t *inst,
   2127                                   const spv_opcode_desc opcodeEntry) {}
   2128 #endif
   2129 
   2130 #if 0
   2131 template <>
   2132 bool idUsage::isValid<OpIsNormal>(const spv_instruction_t *inst,
   2133                                   const spv_opcode_desc opcodeEntry) {}
   2134 #endif
   2135 
   2136 #if 0
   2137 template <>
   2138 bool idUsage::isValid<OpSignBitSet>(const spv_instruction_t *inst,
   2139                                     const spv_opcode_desc opcodeEntry) {}
   2140 #endif
   2141 
   2142 #if 0
   2143 template <>
   2144 bool idUsage::isValid<OpLessOrGreater>(const spv_instruction_t *inst,
   2145                                        const spv_opcode_desc opcodeEntry) {
   2146 }
   2147 #endif
   2148 
   2149 #if 0
   2150 template <>
   2151 bool idUsage::isValid<OpOrdered>(const spv_instruction_t *inst,
   2152                                  const spv_opcode_desc opcodeEntry) {}
   2153 #endif
   2154 
   2155 #if 0
   2156 template <>
   2157 bool idUsage::isValid<OpUnordered>(const spv_instruction_t *inst,
   2158                                    const spv_opcode_desc opcodeEntry) {}
   2159 #endif
   2160 
   2161 #if 0
   2162 template <>
   2163 bool idUsage::isValid<OpLogicalOr>(const spv_instruction_t *inst,
   2164                                    const spv_opcode_desc opcodeEntry) {}
   2165 #endif
   2166 
   2167 #if 0
   2168 template <>
   2169 bool idUsage::isValid<OpLogicalXor>(const spv_instruction_t *inst,
   2170                                     const spv_opcode_desc opcodeEntry) {}
   2171 #endif
   2172 
   2173 #if 0
   2174 template <>
   2175 bool idUsage::isValid<OpLogicalAnd>(const spv_instruction_t *inst,
   2176                                     const spv_opcode_desc opcodeEntry) {}
   2177 #endif
   2178 
   2179 #if 0
   2180 template <>
   2181 bool idUsage::isValid<OpSelect>(const spv_instruction_t *inst,
   2182                                 const spv_opcode_desc opcodeEntry) {}
   2183 #endif
   2184 
   2185 #if 0
   2186 template <>
   2187 bool idUsage::isValid<OpIEqual>(const spv_instruction_t *inst,
   2188                                 const spv_opcode_desc opcodeEntry) {}
   2189 #endif
   2190 
   2191 #if 0
   2192 template <>
   2193 bool idUsage::isValid<OpFOrdEqual>(const spv_instruction_t *inst,
   2194                                    const spv_opcode_desc opcodeEntry) {}
   2195 #endif
   2196 
   2197 #if 0
   2198 template <>
   2199 bool idUsage::isValid<OpFUnordEqual>(const spv_instruction_t *inst,
   2200                                      const spv_opcode_desc opcodeEntry) {}
   2201 #endif
   2202 
   2203 #if 0
   2204 template <>
   2205 bool idUsage::isValid<OpINotEqual>(const spv_instruction_t *inst,
   2206                                    const spv_opcode_desc opcodeEntry) {}
   2207 #endif
   2208 
   2209 #if 0
   2210 template <>
   2211 bool idUsage::isValid<OpFOrdNotEqual>(const spv_instruction_t *inst,
   2212                                       const spv_opcode_desc opcodeEntry) {}
   2213 #endif
   2214 
   2215 #if 0
   2216 template <>
   2217 bool idUsage::isValid<OpFUnordNotEqual>(
   2218     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2219 #endif
   2220 
   2221 #if 0
   2222 template <>
   2223 bool idUsage::isValid<OpULessThan>(const spv_instruction_t *inst,
   2224                                    const spv_opcode_desc opcodeEntry) {}
   2225 #endif
   2226 
   2227 #if 0
   2228 template <>
   2229 bool idUsage::isValid<OpSLessThan>(const spv_instruction_t *inst,
   2230                                    const spv_opcode_desc opcodeEntry) {}
   2231 #endif
   2232 
   2233 #if 0
   2234 template <>
   2235 bool idUsage::isValid<OpFOrdLessThan>(const spv_instruction_t *inst,
   2236                                       const spv_opcode_desc opcodeEntry) {}
   2237 #endif
   2238 
   2239 #if 0
   2240 template <>
   2241 bool idUsage::isValid<OpFUnordLessThan>(
   2242     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2243 #endif
   2244 
   2245 #if 0
   2246 template <>
   2247 bool idUsage::isValid<OpUGreaterThan>(const spv_instruction_t *inst,
   2248                                       const spv_opcode_desc opcodeEntry) {}
   2249 #endif
   2250 
   2251 #if 0
   2252 template <>
   2253 bool idUsage::isValid<OpSGreaterThan>(const spv_instruction_t *inst,
   2254                                       const spv_opcode_desc opcodeEntry) {}
   2255 #endif
   2256 
   2257 #if 0
   2258 template <>
   2259 bool idUsage::isValid<OpFOrdGreaterThan>(
   2260     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2261 #endif
   2262 
   2263 #if 0
   2264 template <>
   2265 bool idUsage::isValid<OpFUnordGreaterThan>(
   2266     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2267 #endif
   2268 
   2269 #if 0
   2270 template <>
   2271 bool idUsage::isValid<OpULessThanEqual>(
   2272     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2273 #endif
   2274 
   2275 #if 0
   2276 template <>
   2277 bool idUsage::isValid<OpSLessThanEqual>(
   2278     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2279 #endif
   2280 
   2281 #if 0
   2282 template <>
   2283 bool idUsage::isValid<OpFOrdLessThanEqual>(
   2284     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2285 #endif
   2286 
   2287 #if 0
   2288 template <>
   2289 bool idUsage::isValid<OpFUnordLessThanEqual>(
   2290     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2291 #endif
   2292 
   2293 #if 0
   2294 template <>
   2295 bool idUsage::isValid<OpUGreaterThanEqual>(
   2296     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2297 #endif
   2298 
   2299 #if 0
   2300 template <>
   2301 bool idUsage::isValid<OpSGreaterThanEqual>(
   2302     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2303 #endif
   2304 
   2305 #if 0
   2306 template <>
   2307 bool idUsage::isValid<OpFOrdGreaterThanEqual>(
   2308     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2309 #endif
   2310 
   2311 #if 0
   2312 template <>
   2313 bool idUsage::isValid<OpFUnordGreaterThanEqual>(
   2314     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2315 #endif
   2316 
   2317 #if 0
   2318 template <>
   2319 bool idUsage::isValid<OpDPdx>(const spv_instruction_t *inst,
   2320                               const spv_opcode_desc opcodeEntry) {}
   2321 #endif
   2322 
   2323 #if 0
   2324 template <>
   2325 bool idUsage::isValid<OpDPdy>(const spv_instruction_t *inst,
   2326                               const spv_opcode_desc opcodeEntry) {}
   2327 #endif
   2328 
   2329 #if 0
   2330 template <>
   2331 bool idUsage::isValid<OpFWidth>(const spv_instruction_t *inst,
   2332                                 const spv_opcode_desc opcodeEntry) {}
   2333 #endif
   2334 
   2335 #if 0
   2336 template <>
   2337 bool idUsage::isValid<OpDPdxFine>(const spv_instruction_t *inst,
   2338                                   const spv_opcode_desc opcodeEntry) {}
   2339 #endif
   2340 
   2341 #if 0
   2342 template <>
   2343 bool idUsage::isValid<OpDPdyFine>(const spv_instruction_t *inst,
   2344                                   const spv_opcode_desc opcodeEntry) {}
   2345 #endif
   2346 
   2347 #if 0
   2348 template <>
   2349 bool idUsage::isValid<OpFwidthFine>(const spv_instruction_t *inst,
   2350                                     const spv_opcode_desc opcodeEntry) {}
   2351 #endif
   2352 
   2353 #if 0
   2354 template <>
   2355 bool idUsage::isValid<OpDPdxCoarse>(const spv_instruction_t *inst,
   2356                                     const spv_opcode_desc opcodeEntry) {}
   2357 #endif
   2358 
   2359 #if 0
   2360 template <>
   2361 bool idUsage::isValid<OpDPdyCoarse>(const spv_instruction_t *inst,
   2362                                     const spv_opcode_desc opcodeEntry) {}
   2363 #endif
   2364 
   2365 #if 0
   2366 template <>
   2367 bool idUsage::isValid<OpFwidthCoarse>(const spv_instruction_t *inst,
   2368                                       const spv_opcode_desc opcodeEntry) {}
   2369 #endif
   2370 
   2371 #if 0
   2372 template <>
   2373 bool idUsage::isValid<OpPhi>(const spv_instruction_t *inst,
   2374                              const spv_opcode_desc opcodeEntry) {}
   2375 #endif
   2376 
   2377 #if 0
   2378 template <>
   2379 bool idUsage::isValid<OpLoopMerge>(const spv_instruction_t *inst,
   2380                                    const spv_opcode_desc opcodeEntry) {}
   2381 #endif
   2382 
   2383 #if 0
   2384 template <>
   2385 bool idUsage::isValid<OpSelectionMerge>(
   2386     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2387 #endif
   2388 
   2389 #if 0
   2390 template <>
   2391 bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
   2392                                 const spv_opcode_desc opcodeEntry) {}
   2393 #endif
   2394 
   2395 #if 0
   2396 template <>
   2397 bool idUsage::isValid<OpBranchConditional>(
   2398     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2399 #endif
   2400 
   2401 #if 0
   2402 template <>
   2403 bool idUsage::isValid<OpSwitch>(const spv_instruction_t *inst,
   2404                                 const spv_opcode_desc opcodeEntry) {}
   2405 #endif
   2406 
   2407 template <>
   2408 bool idUsage::isValid<SpvOpReturnValue>(const spv_instruction_t* inst,
   2409                                         const spv_opcode_desc) {
   2410   auto valueIndex = 1;
   2411   auto value = module_.FindDef(inst->words[valueIndex]);
   2412   if (!value || !value->type_id()) {
   2413     DIAG(valueIndex) << "OpReturnValue Value <id> '" << inst->words[valueIndex]
   2414                      << "' does not represent a value.";
   2415     return false;
   2416   }
   2417   auto valueType = module_.FindDef(value->type_id());
   2418   if (!valueType || SpvOpTypeVoid == valueType->opcode()) {
   2419     DIAG(valueIndex) << "OpReturnValue value's type <id> '" << value->type_id()
   2420                      << "' is missing or void.";
   2421     return false;
   2422   }
   2423   const bool uses_variable_pointer =
   2424       module_.features().variable_pointers ||
   2425       module_.features().variable_pointers_storage_buffer;
   2426   if (addressingModel == SpvAddressingModelLogical &&
   2427       SpvOpTypePointer == valueType->opcode() && !uses_variable_pointer) {
   2428     DIAG(valueIndex)
   2429         << "OpReturnValue value's type <id> '" << value->type_id()
   2430         << "' is a pointer, which is invalid in the Logical addressing model.";
   2431     return false;
   2432   }
   2433   // NOTE: Find OpFunction
   2434   const spv_instruction_t* function = inst - 1;
   2435   while (firstInst != function) {
   2436     if (SpvOpFunction == function->opcode) break;
   2437     function--;
   2438   }
   2439   if (SpvOpFunction != function->opcode) {
   2440     DIAG(valueIndex) << "OpReturnValue is not in a basic block.";
   2441     return false;
   2442   }
   2443   auto returnType = module_.FindDef(function->words[1]);
   2444   if (!returnType || returnType->id() != valueType->id()) {
   2445     DIAG(valueIndex) << "OpReturnValue Value <id> '" << inst->words[valueIndex]
   2446                      << "'s type does not match OpFunction's return type.";
   2447     return false;
   2448   }
   2449   return true;
   2450 }
   2451 
   2452 #if 0
   2453 template <>
   2454 bool idUsage::isValid<OpLifetimeStart>(const spv_instruction_t *inst,
   2455                                        const spv_opcode_desc opcodeEntry) {
   2456 }
   2457 #endif
   2458 
   2459 #if 0
   2460 template <>
   2461 bool idUsage::isValid<OpLifetimeStop>(const spv_instruction_t *inst,
   2462                                       const spv_opcode_desc opcodeEntry) {}
   2463 #endif
   2464 
   2465 #if 0
   2466 template <>
   2467 bool idUsage::isValid<OpAtomicInit>(const spv_instruction_t *inst,
   2468                                     const spv_opcode_desc opcodeEntry) {}
   2469 #endif
   2470 
   2471 #if 0
   2472 template <>
   2473 bool idUsage::isValid<OpAtomicLoad>(const spv_instruction_t *inst,
   2474                                     const spv_opcode_desc opcodeEntry) {}
   2475 #endif
   2476 
   2477 #if 0
   2478 template <>
   2479 bool idUsage::isValid<OpAtomicStore>(const spv_instruction_t *inst,
   2480                                      const spv_opcode_desc opcodeEntry) {}
   2481 #endif
   2482 
   2483 #if 0
   2484 template <>
   2485 bool idUsage::isValid<OpAtomicExchange>(
   2486     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2487 #endif
   2488 
   2489 #if 0
   2490 template <>
   2491 bool idUsage::isValid<OpAtomicCompareExchange>(
   2492     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2493 #endif
   2494 
   2495 #if 0
   2496 template <>
   2497 bool idUsage::isValid<OpAtomicCompareExchangeWeak>(
   2498     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2499 #endif
   2500 
   2501 #if 0
   2502 template <>
   2503 bool idUsage::isValid<OpAtomicIIncrement>(
   2504     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2505 #endif
   2506 
   2507 #if 0
   2508 template <>
   2509 bool idUsage::isValid<OpAtomicIDecrement>(
   2510     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2511 #endif
   2512 
   2513 #if 0
   2514 template <>
   2515 bool idUsage::isValid<OpAtomicIAdd>(const spv_instruction_t *inst,
   2516                                     const spv_opcode_desc opcodeEntry) {}
   2517 #endif
   2518 
   2519 #if 0
   2520 template <>
   2521 bool idUsage::isValid<OpAtomicISub>(const spv_instruction_t *inst,
   2522                                     const spv_opcode_desc opcodeEntry) {}
   2523 #endif
   2524 
   2525 #if 0
   2526 template <>
   2527 bool idUsage::isValid<OpAtomicUMin>(const spv_instruction_t *inst,
   2528                                     const spv_opcode_desc opcodeEntry) {}
   2529 #endif
   2530 
   2531 #if 0
   2532 template <>
   2533 bool idUsage::isValid<OpAtomicUMax>(const spv_instruction_t *inst,
   2534                                     const spv_opcode_desc opcodeEntry) {}
   2535 #endif
   2536 
   2537 #if 0
   2538 template <>
   2539 bool idUsage::isValid<OpAtomicAnd>(const spv_instruction_t *inst,
   2540                                    const spv_opcode_desc opcodeEntry) {}
   2541 #endif
   2542 
   2543 #if 0
   2544 template <>
   2545 bool idUsage::isValid<OpAtomicOr>(const spv_instruction_t *inst,
   2546                                   const spv_opcode_desc opcodeEntry) {}
   2547 #endif
   2548 
   2549 #if 0
   2550 template <>
   2551 bool idUsage::isValid<OpAtomicXor>(const spv_instruction_t *inst,
   2552                                    const spv_opcode_desc opcodeEntry) {}
   2553 #endif
   2554 
   2555 #if 0
   2556 template <>
   2557 bool idUsage::isValid<OpAtomicIMin>(const spv_instruction_t *inst,
   2558                                     const spv_opcode_desc opcodeEntry) {}
   2559 #endif
   2560 
   2561 #if 0
   2562 template <>
   2563 bool idUsage::isValid<OpAtomicIMax>(const spv_instruction_t *inst,
   2564                                     const spv_opcode_desc opcodeEntry) {}
   2565 #endif
   2566 
   2567 #if 0
   2568 template <>
   2569 bool idUsage::isValid<OpEmitStreamVertex>(
   2570     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2571 #endif
   2572 
   2573 #if 0
   2574 template <>
   2575 bool idUsage::isValid<OpEndStreamPrimitive>(
   2576     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2577 #endif
   2578 
   2579 #if 0
   2580 template <>
   2581 bool idUsage::isValid<OpGroupAsyncCopy>(
   2582     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2583 #endif
   2584 
   2585 #if 0
   2586 template <>
   2587 bool idUsage::isValid<OpGroupWaitEvents>(
   2588     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2589 #endif
   2590 
   2591 #if 0
   2592 template <>
   2593 bool idUsage::isValid<OpGroupAll>(const spv_instruction_t *inst,
   2594                                   const spv_opcode_desc opcodeEntry) {}
   2595 #endif
   2596 
   2597 #if 0
   2598 template <>
   2599 bool idUsage::isValid<OpGroupAny>(const spv_instruction_t *inst,
   2600                                   const spv_opcode_desc opcodeEntry) {}
   2601 #endif
   2602 
   2603 #if 0
   2604 template <>
   2605 bool idUsage::isValid<OpGroupBroadcast>(
   2606     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2607 #endif
   2608 
   2609 #if 0
   2610 template <>
   2611 bool idUsage::isValid<OpGroupIAdd>(const spv_instruction_t *inst,
   2612                                    const spv_opcode_desc opcodeEntry) {}
   2613 #endif
   2614 
   2615 #if 0
   2616 template <>
   2617 bool idUsage::isValid<OpGroupFAdd>(const spv_instruction_t *inst,
   2618                                    const spv_opcode_desc opcodeEntry) {}
   2619 #endif
   2620 
   2621 #if 0
   2622 template <>
   2623 bool idUsage::isValid<OpGroupFMin>(const spv_instruction_t *inst,
   2624                                    const spv_opcode_desc opcodeEntry) {}
   2625 #endif
   2626 
   2627 #if 0
   2628 template <>
   2629 bool idUsage::isValid<OpGroupUMin>(const spv_instruction_t *inst,
   2630                                    const spv_opcode_desc opcodeEntry) {}
   2631 #endif
   2632 
   2633 #if 0
   2634 template <>
   2635 bool idUsage::isValid<OpGroupSMin>(const spv_instruction_t *inst,
   2636                                    const spv_opcode_desc opcodeEntry) {}
   2637 #endif
   2638 
   2639 #if 0
   2640 template <>
   2641 bool idUsage::isValid<OpGroupFMax>(const spv_instruction_t *inst,
   2642                                    const spv_opcode_desc opcodeEntry) {}
   2643 #endif
   2644 
   2645 #if 0
   2646 template <>
   2647 bool idUsage::isValid<OpGroupUMax>(const spv_instruction_t *inst,
   2648                                    const spv_opcode_desc opcodeEntry) {}
   2649 #endif
   2650 
   2651 #if 0
   2652 template <>
   2653 bool idUsage::isValid<OpGroupSMax>(const spv_instruction_t *inst,
   2654                                    const spv_opcode_desc opcodeEntry) {}
   2655 #endif
   2656 
   2657 #if 0
   2658 template <>
   2659 bool idUsage::isValid<OpEnqueueMarker>(const spv_instruction_t *inst,
   2660                                        const spv_opcode_desc opcodeEntry) {
   2661 }
   2662 #endif
   2663 
   2664 #if 0
   2665 template <>
   2666 bool idUsage::isValid<OpEnqueueKernel>(const spv_instruction_t *inst,
   2667                                        const spv_opcode_desc opcodeEntry) {
   2668 }
   2669 #endif
   2670 
   2671 #if 0
   2672 template <>
   2673 bool idUsage::isValid<OpGetKernelNDrangeSubGroupCount>(
   2674     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2675 #endif
   2676 
   2677 #if 0
   2678 template <>
   2679 bool idUsage::isValid<OpGetKernelNDrangeMaxSubGroupSize>(
   2680     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2681 #endif
   2682 
   2683 #if 0
   2684 template <>
   2685 bool idUsage::isValid<OpGetKernelWorkGroupSize>(
   2686     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2687 #endif
   2688 
   2689 #if 0
   2690 template <>
   2691 bool idUsage::isValid<OpGetKernelPreferredWorkGroupSizeMultiple>(
   2692     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2693 #endif
   2694 
   2695 #if 0
   2696 template <>
   2697 bool idUsage::isValid<OpRetainEvent>(const spv_instruction_t *inst,
   2698                                      const spv_opcode_desc opcodeEntry) {}
   2699 #endif
   2700 
   2701 #if 0
   2702 template <>
   2703 bool idUsage::isValid<OpReleaseEvent>(const spv_instruction_t *inst,
   2704                                       const spv_opcode_desc opcodeEntry) {}
   2705 #endif
   2706 
   2707 #if 0
   2708 template <>
   2709 bool idUsage::isValid<OpCreateUserEvent>(
   2710     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2711 #endif
   2712 
   2713 #if 0
   2714 template <>
   2715 bool idUsage::isValid<OpIsValidEvent>(const spv_instruction_t *inst,
   2716                                       const spv_opcode_desc opcodeEntry) {}
   2717 #endif
   2718 
   2719 #if 0
   2720 template <>
   2721 bool idUsage::isValid<OpSetUserEventStatus>(
   2722     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2723 #endif
   2724 
   2725 #if 0
   2726 template <>
   2727 bool idUsage::isValid<OpCaptureEventProfilingInfo>(
   2728     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2729 #endif
   2730 
   2731 #if 0
   2732 template <>
   2733 bool idUsage::isValid<OpGetDefaultQueue>(
   2734     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2735 #endif
   2736 
   2737 #if 0
   2738 template <>
   2739 bool idUsage::isValid<OpBuildNDRange>(const spv_instruction_t *inst,
   2740                                       const spv_opcode_desc opcodeEntry) {}
   2741 #endif
   2742 
   2743 #if 0
   2744 template <>
   2745 bool idUsage::isValid<OpReadPipe>(const spv_instruction_t *inst,
   2746                                   const spv_opcode_desc opcodeEntry) {}
   2747 #endif
   2748 
   2749 #if 0
   2750 template <>
   2751 bool idUsage::isValid<OpWritePipe>(const spv_instruction_t *inst,
   2752                                    const spv_opcode_desc opcodeEntry) {}
   2753 #endif
   2754 
   2755 #if 0
   2756 template <>
   2757 bool idUsage::isValid<OpReservedReadPipe>(
   2758     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2759 #endif
   2760 
   2761 #if 0
   2762 template <>
   2763 bool idUsage::isValid<OpReservedWritePipe>(
   2764     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2765 #endif
   2766 
   2767 #if 0
   2768 template <>
   2769 bool idUsage::isValid<OpReserveReadPipePackets>(
   2770     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2771 #endif
   2772 
   2773 #if 0
   2774 template <>
   2775 bool idUsage::isValid<OpReserveWritePipePackets>(
   2776     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2777 #endif
   2778 
   2779 #if 0
   2780 template <>
   2781 bool idUsage::isValid<OpCommitReadPipe>(
   2782     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2783 #endif
   2784 
   2785 #if 0
   2786 template <>
   2787 bool idUsage::isValid<OpCommitWritePipe>(
   2788     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2789 #endif
   2790 
   2791 #if 0
   2792 template <>
   2793 bool idUsage::isValid<OpIsValidReserveId>(
   2794     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2795 #endif
   2796 
   2797 #if 0
   2798 template <>
   2799 bool idUsage::isValid<OpGetNumPipePackets>(
   2800     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2801 #endif
   2802 
   2803 #if 0
   2804 template <>
   2805 bool idUsage::isValid<OpGetMaxPipePackets>(
   2806     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2807 #endif
   2808 
   2809 #if 0
   2810 template <>
   2811 bool idUsage::isValid<OpGroupReserveReadPipePackets>(
   2812     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2813 #endif
   2814 
   2815 #if 0
   2816 template <>
   2817 bool idUsage::isValid<OpGroupReserveWritePipePackets>(
   2818     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2819 #endif
   2820 
   2821 #if 0
   2822 template <>
   2823 bool idUsage::isValid<OpGroupCommitReadPipe>(
   2824     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2825 #endif
   2826 
   2827 #if 0
   2828 template <>
   2829 bool idUsage::isValid<OpGroupCommitWritePipe>(
   2830     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2831 #endif
   2832 
   2833 #undef DIAG
   2834 
   2835 bool idUsage::isValid(const spv_instruction_t* inst) {
   2836   spv_opcode_desc opcodeEntry = nullptr;
   2837   if (spvOpcodeTableValueLookup(opcodeTable, inst->opcode, &opcodeEntry))
   2838     return false;
   2839 #define CASE(OpCode) \
   2840   case Spv##OpCode:  \
   2841     return isValid<Spv##OpCode>(inst, opcodeEntry);
   2842 #define TODO(OpCode) \
   2843   case Spv##OpCode:  \
   2844     return true;
   2845   switch (inst->opcode) {
   2846     TODO(OpUndef)
   2847     CASE(OpMemberName)
   2848     CASE(OpLine)
   2849     CASE(OpDecorate)
   2850     CASE(OpMemberDecorate)
   2851     CASE(OpGroupDecorate)
   2852     CASE(OpGroupMemberDecorate)
   2853     TODO(OpExtInst)
   2854     CASE(OpEntryPoint)
   2855     CASE(OpExecutionMode)
   2856     CASE(OpTypeVector)
   2857     CASE(OpTypeMatrix)
   2858     CASE(OpTypeSampler)
   2859     CASE(OpTypeArray)
   2860     CASE(OpTypeRuntimeArray)
   2861     CASE(OpTypeStruct)
   2862     CASE(OpTypePointer)
   2863     CASE(OpTypeFunction)
   2864     CASE(OpTypePipe)
   2865     CASE(OpConstantTrue)
   2866     CASE(OpConstantFalse)
   2867     CASE(OpConstantComposite)
   2868     CASE(OpConstantSampler)
   2869     CASE(OpConstantNull)
   2870     CASE(OpSpecConstantTrue)
   2871     CASE(OpSpecConstantFalse)
   2872     CASE(OpSpecConstantComposite)
   2873     CASE(OpSampledImage)
   2874     TODO(OpSpecConstantOp)
   2875     CASE(OpVariable)
   2876     CASE(OpLoad)
   2877     CASE(OpStore)
   2878     CASE(OpCopyMemory)
   2879     CASE(OpCopyMemorySized)
   2880     CASE(OpAccessChain)
   2881     CASE(OpInBoundsAccessChain)
   2882     CASE(OpPtrAccessChain)
   2883     CASE(OpInBoundsPtrAccessChain)
   2884     TODO(OpArrayLength)
   2885     TODO(OpGenericPtrMemSemantics)
   2886     CASE(OpFunction)
   2887     CASE(OpFunctionParameter)
   2888     CASE(OpFunctionCall)
   2889     TODO(OpConvertUToF)
   2890     TODO(OpConvertFToS)
   2891     TODO(OpConvertSToF)
   2892     TODO(OpUConvert)
   2893     TODO(OpSConvert)
   2894     TODO(OpFConvert)
   2895     TODO(OpConvertPtrToU)
   2896     TODO(OpConvertUToPtr)
   2897     TODO(OpPtrCastToGeneric)
   2898     TODO(OpGenericCastToPtr)
   2899     TODO(OpBitcast)
   2900     TODO(OpGenericCastToPtrExplicit)
   2901     TODO(OpSatConvertSToU)
   2902     TODO(OpSatConvertUToS)
   2903     TODO(OpVectorExtractDynamic)
   2904     TODO(OpVectorInsertDynamic)
   2905     TODO(OpVectorShuffle)
   2906     TODO(OpCompositeConstruct)
   2907     CASE(OpCompositeExtract)
   2908     CASE(OpCompositeInsert)
   2909     TODO(OpCopyObject)
   2910     TODO(OpTranspose)
   2911     TODO(OpSNegate)
   2912     TODO(OpFNegate)
   2913     TODO(OpNot)
   2914     TODO(OpIAdd)
   2915     TODO(OpFAdd)
   2916     TODO(OpISub)
   2917     TODO(OpFSub)
   2918     TODO(OpIMul)
   2919     TODO(OpFMul)
   2920     TODO(OpUDiv)
   2921     TODO(OpSDiv)
   2922     TODO(OpFDiv)
   2923     TODO(OpUMod)
   2924     TODO(OpSRem)
   2925     TODO(OpSMod)
   2926     TODO(OpFRem)
   2927     TODO(OpFMod)
   2928     TODO(OpVectorTimesScalar)
   2929     TODO(OpMatrixTimesScalar)
   2930     TODO(OpVectorTimesMatrix)
   2931     TODO(OpMatrixTimesVector)
   2932     TODO(OpMatrixTimesMatrix)
   2933     TODO(OpOuterProduct)
   2934     TODO(OpDot)
   2935     TODO(OpShiftRightLogical)
   2936     TODO(OpShiftRightArithmetic)
   2937     TODO(OpShiftLeftLogical)
   2938     TODO(OpBitwiseOr)
   2939     TODO(OpBitwiseXor)
   2940     TODO(OpBitwiseAnd)
   2941     TODO(OpAny)
   2942     TODO(OpAll)
   2943     TODO(OpIsNan)
   2944     TODO(OpIsInf)
   2945     TODO(OpIsFinite)
   2946     TODO(OpIsNormal)
   2947     TODO(OpSignBitSet)
   2948     TODO(OpLessOrGreater)
   2949     TODO(OpOrdered)
   2950     TODO(OpUnordered)
   2951     TODO(OpLogicalOr)
   2952     TODO(OpLogicalAnd)
   2953     TODO(OpSelect)
   2954     TODO(OpIEqual)
   2955     TODO(OpFOrdEqual)
   2956     TODO(OpFUnordEqual)
   2957     TODO(OpINotEqual)
   2958     TODO(OpFOrdNotEqual)
   2959     TODO(OpFUnordNotEqual)
   2960     TODO(OpULessThan)
   2961     TODO(OpSLessThan)
   2962     TODO(OpFOrdLessThan)
   2963     TODO(OpFUnordLessThan)
   2964     TODO(OpUGreaterThan)
   2965     TODO(OpSGreaterThan)
   2966     TODO(OpFOrdGreaterThan)
   2967     TODO(OpFUnordGreaterThan)
   2968     TODO(OpULessThanEqual)
   2969     TODO(OpSLessThanEqual)
   2970     TODO(OpFOrdLessThanEqual)
   2971     TODO(OpFUnordLessThanEqual)
   2972     TODO(OpUGreaterThanEqual)
   2973     TODO(OpSGreaterThanEqual)
   2974     TODO(OpFOrdGreaterThanEqual)
   2975     TODO(OpFUnordGreaterThanEqual)
   2976     TODO(OpDPdx)
   2977     TODO(OpDPdy)
   2978     TODO(OpFwidth)
   2979     TODO(OpDPdxFine)
   2980     TODO(OpDPdyFine)
   2981     TODO(OpFwidthFine)
   2982     TODO(OpDPdxCoarse)
   2983     TODO(OpDPdyCoarse)
   2984     TODO(OpFwidthCoarse)
   2985     TODO(OpPhi)
   2986     TODO(OpLoopMerge)
   2987     TODO(OpSelectionMerge)
   2988     TODO(OpBranch)
   2989     TODO(OpBranchConditional)
   2990     TODO(OpSwitch)
   2991     CASE(OpReturnValue)
   2992     TODO(OpLifetimeStart)
   2993     TODO(OpLifetimeStop)
   2994     TODO(OpAtomicLoad)
   2995     TODO(OpAtomicStore)
   2996     TODO(OpAtomicExchange)
   2997     TODO(OpAtomicCompareExchange)
   2998     TODO(OpAtomicCompareExchangeWeak)
   2999     TODO(OpAtomicIIncrement)
   3000     TODO(OpAtomicIDecrement)
   3001     TODO(OpAtomicIAdd)
   3002     TODO(OpAtomicISub)
   3003     TODO(OpAtomicUMin)
   3004     TODO(OpAtomicUMax)
   3005     TODO(OpAtomicAnd)
   3006     TODO(OpAtomicOr)
   3007     TODO(OpAtomicSMin)
   3008     TODO(OpAtomicSMax)
   3009     TODO(OpEmitStreamVertex)
   3010     TODO(OpEndStreamPrimitive)
   3011     TODO(OpGroupAsyncCopy)
   3012     TODO(OpGroupWaitEvents)
   3013     TODO(OpGroupAll)
   3014     TODO(OpGroupAny)
   3015     TODO(OpGroupBroadcast)
   3016     TODO(OpGroupIAdd)
   3017     TODO(OpGroupFAdd)
   3018     TODO(OpGroupFMin)
   3019     TODO(OpGroupUMin)
   3020     TODO(OpGroupSMin)
   3021     TODO(OpGroupFMax)
   3022     TODO(OpGroupUMax)
   3023     TODO(OpGroupSMax)
   3024     TODO(OpEnqueueMarker)
   3025     TODO(OpEnqueueKernel)
   3026     TODO(OpGetKernelNDrangeSubGroupCount)
   3027     TODO(OpGetKernelNDrangeMaxSubGroupSize)
   3028     TODO(OpGetKernelWorkGroupSize)
   3029     TODO(OpGetKernelPreferredWorkGroupSizeMultiple)
   3030     TODO(OpRetainEvent)
   3031     TODO(OpReleaseEvent)
   3032     TODO(OpCreateUserEvent)
   3033     TODO(OpIsValidEvent)
   3034     TODO(OpSetUserEventStatus)
   3035     TODO(OpCaptureEventProfilingInfo)
   3036     TODO(OpGetDefaultQueue)
   3037     TODO(OpBuildNDRange)
   3038     TODO(OpReadPipe)
   3039     TODO(OpWritePipe)
   3040     TODO(OpReservedReadPipe)
   3041     TODO(OpReservedWritePipe)
   3042     TODO(OpReserveReadPipePackets)
   3043     TODO(OpReserveWritePipePackets)
   3044     TODO(OpCommitReadPipe)
   3045     TODO(OpCommitWritePipe)
   3046     TODO(OpIsValidReserveId)
   3047     TODO(OpGetNumPipePackets)
   3048     TODO(OpGetMaxPipePackets)
   3049     TODO(OpGroupReserveReadPipePackets)
   3050     TODO(OpGroupReserveWritePipePackets)
   3051     TODO(OpGroupCommitReadPipe)
   3052     TODO(OpGroupCommitWritePipe)
   3053     default:
   3054       return true;
   3055   }
   3056 #undef TODO
   3057 #undef CASE
   3058 }
   3059 // This function takes the opcode of an instruction and returns
   3060 // a function object that will return true if the index
   3061 // of the operand can be forwarad declared. This function will
   3062 // used in the SSA validation stage of the pipeline
   3063 function<bool(unsigned)> getCanBeForwardDeclaredFunction(SpvOp opcode) {
   3064   function<bool(unsigned index)> out;
   3065   switch (opcode) {
   3066     case SpvOpExecutionMode:
   3067     case SpvOpEntryPoint:
   3068     case SpvOpName:
   3069     case SpvOpMemberName:
   3070     case SpvOpSelectionMerge:
   3071     case SpvOpDecorate:
   3072     case SpvOpMemberDecorate:
   3073     case SpvOpTypeStruct:
   3074     case SpvOpBranch:
   3075     case SpvOpLoopMerge:
   3076       out = [](unsigned) { return true; };
   3077       break;
   3078     case SpvOpGroupDecorate:
   3079     case SpvOpGroupMemberDecorate:
   3080     case SpvOpBranchConditional:
   3081     case SpvOpSwitch:
   3082       out = [](unsigned index) { return index != 0; };
   3083       break;
   3084 
   3085     case SpvOpFunctionCall:
   3086       // The Function parameter.
   3087       out = [](unsigned index) { return index == 2; };
   3088       break;
   3089 
   3090     case SpvOpPhi:
   3091       out = [](unsigned index) { return index > 1; };
   3092       break;
   3093 
   3094     case SpvOpEnqueueKernel:
   3095       // The Invoke parameter.
   3096       out = [](unsigned index) { return index == 8; };
   3097       break;
   3098 
   3099     case SpvOpGetKernelNDrangeSubGroupCount:
   3100     case SpvOpGetKernelNDrangeMaxSubGroupSize:
   3101       // The Invoke parameter.
   3102       out = [](unsigned index) { return index == 3; };
   3103       break;
   3104 
   3105     case SpvOpGetKernelWorkGroupSize:
   3106     case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
   3107       // The Invoke parameter.
   3108       out = [](unsigned index) { return index == 2; };
   3109       break;
   3110     case SpvOpTypeForwardPointer:
   3111       out = [](unsigned index) { return index == 0; };
   3112       break;
   3113     default:
   3114       out = [](unsigned) { return false; };
   3115       break;
   3116   }
   3117   return out;
   3118 }
   3119 }  // anonymous namespace
   3120 
   3121 namespace libspirv {
   3122 
   3123 spv_result_t UpdateIdUse(ValidationState_t& _) {
   3124   for (const auto& inst : _.ordered_instructions()) {
   3125     for (auto& operand : inst.operands()) {
   3126       const spv_operand_type_t& type = operand.type;
   3127       const uint32_t operand_id = inst.word(operand.offset);
   3128       if (spvIsIdType(type) && type != SPV_OPERAND_TYPE_RESULT_ID) {
   3129         if (auto def = _.FindDef(operand_id))
   3130           def->RegisterUse(&inst, operand.offset);
   3131       }
   3132     }
   3133   }
   3134   return SPV_SUCCESS;
   3135 }
   3136 
   3137 /// This function checks all ID definitions dominate their use in the CFG.
   3138 ///
   3139 /// This function will iterate over all ID definitions that are defined in the
   3140 /// functions of a module and make sure that the definitions appear in a
   3141 /// block that dominates their use.
   3142 ///
   3143 /// NOTE: This function does NOT check module scoped functions which are
   3144 /// checked during the initial binary parse in the IdPass below
   3145 spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) {
   3146   unordered_set<const Instruction*> phi_instructions;
   3147   for (const auto& definition : _.all_definitions()) {
   3148     // Check only those definitions defined in a function
   3149     if (const Function* func = definition.second->function()) {
   3150       if (const BasicBlock* block = definition.second->block()) {
   3151         if (!block->reachable()) continue;
   3152         // If the Id is defined within a block then make sure all references to
   3153         // that Id appear in a blocks that are dominated by the defining block
   3154         for (auto& use_index_pair : definition.second->uses()) {
   3155           const Instruction* use = use_index_pair.first;
   3156           if (const BasicBlock* use_block = use->block()) {
   3157             if (use_block->reachable() == false) continue;
   3158             if (use->opcode() == SpvOpPhi) {
   3159               phi_instructions.insert(use);
   3160             } else if (!block->dominates(*use->block())) {
   3161               return _.diag(SPV_ERROR_INVALID_ID)
   3162                      << "ID " << _.getIdName(definition.first)
   3163                      << " defined in block " << _.getIdName(block->id())
   3164                      << " does not dominate its use in block "
   3165                      << _.getIdName(use_block->id());
   3166             }
   3167           }
   3168         }
   3169       } else {
   3170         // If the Ids defined within a function but not in a block(i.e. function
   3171         // parameters, block ids), then make sure all references to that Id
   3172         // appear within the same function
   3173         for (auto use : definition.second->uses()) {
   3174           const Instruction* inst = use.first;
   3175           if (inst->function() && inst->function() != func) {
   3176             return _.diag(SPV_ERROR_INVALID_ID)
   3177                    << "ID " << _.getIdName(definition.first)
   3178                    << " used in function "
   3179                    << _.getIdName(inst->function()->id())
   3180                    << " is used outside of it's defining function "
   3181                    << _.getIdName(func->id());
   3182           }
   3183         }
   3184       }
   3185     }
   3186     // NOTE: Ids defined outside of functions must appear before they are used
   3187     // This check is being performed in the IdPass function
   3188   }
   3189 
   3190   // Check all OpPhi parent blocks are dominated by the variable's defining
   3191   // blocks
   3192   for (const Instruction* phi : phi_instructions) {
   3193     if (phi->block()->reachable() == false) continue;
   3194     for (size_t i = 3; i < phi->operands().size(); i += 2) {
   3195       const Instruction* variable = _.FindDef(phi->word(i));
   3196       const BasicBlock* parent =
   3197           phi->function()->GetBlock(phi->word(i + 1)).first;
   3198       if (variable->block() && !variable->block()->dominates(*parent)) {
   3199         return _.diag(SPV_ERROR_INVALID_ID)
   3200                << "In OpPhi instruction " << _.getIdName(phi->id()) << ", ID "
   3201                << _.getIdName(variable->id())
   3202                << " definition does not dominate its parent "
   3203                << _.getIdName(parent->id());
   3204       }
   3205     }
   3206   }
   3207 
   3208   return SPV_SUCCESS;
   3209 }
   3210 
   3211 // Performs SSA validation on the IDs of an instruction. The
   3212 // can_have_forward_declared_ids  functor should return true if the
   3213 // instruction operand's ID can be forward referenced.
   3214 spv_result_t IdPass(ValidationState_t& _,
   3215                     const spv_parsed_instruction_t* inst) {
   3216   auto can_have_forward_declared_ids =
   3217       getCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
   3218 
   3219   // Keep track of a result id defined by this instruction.  0 means it
   3220   // does not define an id.
   3221   uint32_t result_id = 0;
   3222 
   3223   for (unsigned i = 0; i < inst->num_operands; i++) {
   3224     const spv_parsed_operand_t& operand = inst->operands[i];
   3225     const spv_operand_type_t& type = operand.type;
   3226     // We only care about Id operands, which are a single word.
   3227     const uint32_t operand_word = inst->words[operand.offset];
   3228 
   3229     auto ret = SPV_ERROR_INTERNAL;
   3230     switch (type) {
   3231       case SPV_OPERAND_TYPE_RESULT_ID:
   3232         // NOTE: Multiple Id definitions are being checked by the binary parser.
   3233         //
   3234         // Defer undefined-forward-reference removal until after we've analyzed
   3235         // the remaining operands to this instruction.  Deferral only matters
   3236         // for
   3237         // OpPhi since it's the only case where it defines its own forward
   3238         // reference.  Other instructions that can have forward references
   3239         // either don't define a value or the forward reference is to a function
   3240         // Id (and hence defined outside of a function body).
   3241         result_id = operand_word;
   3242         // NOTE: The result Id is added (in RegisterInstruction) *after* all of
   3243         // the other Ids have been checked to avoid premature use in the same
   3244         // instruction.
   3245         ret = SPV_SUCCESS;
   3246         break;
   3247       case SPV_OPERAND_TYPE_ID:
   3248       case SPV_OPERAND_TYPE_TYPE_ID:
   3249       case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
   3250       case SPV_OPERAND_TYPE_SCOPE_ID:
   3251         if (_.IsDefinedId(operand_word)) {
   3252           ret = SPV_SUCCESS;
   3253         } else if (can_have_forward_declared_ids(i)) {
   3254           ret = _.ForwardDeclareId(operand_word);
   3255         } else {
   3256           ret = _.diag(SPV_ERROR_INVALID_ID) << "ID "
   3257                                              << _.getIdName(operand_word)
   3258                                              << " has not been defined";
   3259         }
   3260         break;
   3261       default:
   3262         ret = SPV_SUCCESS;
   3263         break;
   3264     }
   3265     if (SPV_SUCCESS != ret) {
   3266       return ret;
   3267     }
   3268   }
   3269   if (result_id) {
   3270     _.RemoveIfForwardDeclared(result_id);
   3271   }
   3272   _.RegisterInstruction(*inst);
   3273   return SPV_SUCCESS;
   3274 }
   3275 }  // namespace libspirv
   3276 
   3277 spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts,
   3278                                        const uint64_t instCount,
   3279                                        const spv_opcode_table opcodeTable,
   3280                                        const spv_operand_table operandTable,
   3281                                        const spv_ext_inst_table extInstTable,
   3282                                        const libspirv::ValidationState_t& state,
   3283                                        spv_position position) {
   3284   idUsage idUsage(opcodeTable, operandTable, extInstTable, pInsts, instCount,
   3285                   state.memory_model(), state.addressing_model(), state,
   3286                   state.entry_points(), position, state.context()->consumer);
   3287   for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
   3288     if (!idUsage.isValid(&pInsts[instIndex])) return SPV_ERROR_INVALID_ID;
   3289     position->index += pInsts[instIndex].words.size();
   3290   }
   3291   return SPV_SUCCESS;
   3292 }
   3293