Home | History | Annotate | Download | only in source
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a
      4 // copy of this software and/or associated documentation files (the
      5 // "Materials"), to deal in the Materials without restriction, including
      6 // without limitation the rights to use, copy, modify, merge, publish,
      7 // distribute, sublicense, and/or sell copies of the Materials, and to
      8 // permit persons to whom the Materials are furnished to do so, subject to
      9 // the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included
     12 // in all copies or substantial portions of the Materials.
     13 //
     14 // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
     15 // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
     16 // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
     17 //    https://www.khronos.org/registry/
     18 //
     19 // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     22 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     23 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25 // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
     26 
     27 #include "validate.h"
     28 
     29 #include <cassert>
     30 
     31 #include <iostream>
     32 #include <unordered_map>
     33 #include <vector>
     34 
     35 #include "diagnostic.h"
     36 #include "instruction.h"
     37 #include "opcode.h"
     38 #include "spirv-tools/libspirv.h"
     39 #include "val/ValidationState.h"
     40 
     41 #define spvCheck(condition, action) \
     42   if (condition) {                  \
     43     action;                         \
     44   }
     45 
     46 using UseDefTracker = libspirv::ValidationState_t::UseDefTracker;
     47 
     48 namespace {
     49 
     50 class idUsage {
     51  public:
     52   idUsage(const spv_opcode_table opcodeTableArg,
     53           const spv_operand_table operandTableArg,
     54           const spv_ext_inst_table extInstTableArg,
     55           const spv_instruction_t* pInsts, const uint64_t instCountArg,
     56           const SpvMemoryModel memoryModelArg,
     57           const SpvAddressingModel addressingModelArg,
     58           const UseDefTracker& usedefs,
     59           const std::vector<uint32_t>& entry_points, spv_position positionArg,
     60           spv_diagnostic* pDiagnosticArg)
     61       : opcodeTable(opcodeTableArg),
     62         operandTable(operandTableArg),
     63         extInstTable(extInstTableArg),
     64         firstInst(pInsts),
     65         instCount(instCountArg),
     66         memoryModel(memoryModelArg),
     67         addressingModel(addressingModelArg),
     68         position(positionArg),
     69         pDiagnostic(pDiagnosticArg),
     70         usedefs_(usedefs),
     71         entry_points_(entry_points) {}
     72 
     73   bool isValid(const spv_instruction_t* inst);
     74 
     75   template <SpvOp>
     76   bool isValid(const spv_instruction_t* inst, const spv_opcode_desc);
     77 
     78  private:
     79   const spv_opcode_table opcodeTable;
     80   const spv_operand_table operandTable;
     81   const spv_ext_inst_table extInstTable;
     82   const spv_instruction_t* const firstInst;
     83   const uint64_t instCount;
     84   const SpvMemoryModel memoryModel;
     85   const SpvAddressingModel addressingModel;
     86   spv_position position;
     87   spv_diagnostic* pDiagnostic;
     88   UseDefTracker usedefs_;
     89   std::vector<uint32_t> entry_points_;
     90 };
     91 
     92 #define DIAG(INDEX)         \
     93   position->index += INDEX; \
     94   DIAGNOSTIC
     95 
     96 #if 0
     97 template <>
     98 bool idUsage::isValid<SpvOpUndef>(const spv_instruction_t *inst,
     99                                   const spv_opcode_desc) {
    100   assert(0 && "Unimplemented!");
    101   return false;
    102 }
    103 #endif  // 0
    104 
    105 template <>
    106 bool idUsage::isValid<SpvOpMemberName>(const spv_instruction_t* inst,
    107                                        const spv_opcode_desc) {
    108   auto typeIndex = 1;
    109   auto type = usedefs_.FindDef(inst->words[typeIndex]);
    110   if (!type.first || SpvOpTypeStruct != type.second.opcode) {
    111     DIAG(typeIndex) << "OpMemberName Type <id> '" << inst->words[typeIndex]
    112                     << "' is not a struct type.";
    113     return false;
    114   }
    115   auto memberIndex = 2;
    116   auto member = inst->words[memberIndex];
    117   auto memberCount = (uint32_t)(type.second.words.size() - 2);
    118   spvCheck(memberCount <= member, DIAG(memberIndex)
    119                                       << "OpMemberName Member <id> '"
    120                                       << inst->words[memberIndex]
    121                                       << "' index is larger than Type <id> '"
    122                                       << type.second.id << "'s member count.";
    123            return false);
    124   return true;
    125 }
    126 
    127 template <>
    128 bool idUsage::isValid<SpvOpLine>(const spv_instruction_t* inst,
    129                                  const spv_opcode_desc) {
    130   auto fileIndex = 1;
    131   auto file = usedefs_.FindDef(inst->words[fileIndex]);
    132   if (!file.first || SpvOpString != file.second.opcode) {
    133     DIAG(fileIndex) << "OpLine Target <id> '" << inst->words[fileIndex]
    134                     << "' is not an OpString.";
    135     return false;
    136   }
    137   return true;
    138 }
    139 
    140 template <>
    141 bool idUsage::isValid<SpvOpMemberDecorate>(const spv_instruction_t* inst,
    142                                            const spv_opcode_desc) {
    143   auto structTypeIndex = 1;
    144   auto structType = usedefs_.FindDef(inst->words[structTypeIndex]);
    145   if (!structType.first || SpvOpTypeStruct != structType.second.opcode) {
    146     DIAG(structTypeIndex) << "OpMemberDecorate Structure type <id> '"
    147                           << inst->words[structTypeIndex]
    148                           << "' is not a struct type.";
    149     return false;
    150   }
    151   auto memberIndex = 2;
    152   auto member = inst->words[memberIndex];
    153   auto memberCount = static_cast<uint32_t>(structType.second.words.size() - 2);
    154   spvCheck(memberCount < member, DIAG(memberIndex)
    155                                      << "OpMemberDecorate Structure type <id> '"
    156                                      << inst->words[memberIndex]
    157                                      << "' member count is less than Member";
    158            return false);
    159   return true;
    160 }
    161 
    162 template <>
    163 bool idUsage::isValid<SpvOpGroupDecorate>(const spv_instruction_t* inst,
    164                                           const spv_opcode_desc) {
    165   auto decorationGroupIndex = 1;
    166   auto decorationGroup = usedefs_.FindDef(inst->words[decorationGroupIndex]);
    167   if (!decorationGroup.first ||
    168       SpvOpDecorationGroup != decorationGroup.second.opcode) {
    169     DIAG(decorationGroupIndex) << "OpGroupDecorate Decoration group <id> '"
    170                                << inst->words[decorationGroupIndex]
    171                                << "' is not a decoration group.";
    172     return false;
    173   }
    174   return true;
    175 }
    176 
    177 #if 0
    178 template <>
    179 bool idUsage::isValid<SpvOpGroupMemberDecorate>(
    180     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
    181 #endif  // 0
    182 
    183 #if 0
    184 template <>
    185 bool idUsage::isValid<SpvOpExtInst>(const spv_instruction_t *inst,
    186                                     const spv_opcode_desc opcodeEntry) {}
    187 #endif  // 0
    188 
    189 template <>
    190 bool idUsage::isValid<SpvOpEntryPoint>(const spv_instruction_t* inst,
    191                                        const spv_opcode_desc) {
    192   auto entryPointIndex = 2;
    193   auto entryPoint = usedefs_.FindDef(inst->words[entryPointIndex]);
    194   if (!entryPoint.first || SpvOpFunction != entryPoint.second.opcode) {
    195     DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    196                           << inst->words[entryPointIndex]
    197                           << "' is not a function.";
    198     return false;
    199   }
    200   // don't check kernel function signatures
    201   auto executionModel = inst->words[1];
    202   if (executionModel != SpvExecutionModelKernel) {
    203     // TODO: Check the entry point signature is void main(void), may be subject
    204     // to change
    205     auto entryPointType = usedefs_.FindDef(entryPoint.second.words[4]);
    206     if (!entryPointType.first || 3 != entryPointType.second.words.size()) {
    207       DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    208                             << inst->words[entryPointIndex]
    209                             << "'s function parameter count is not zero.";
    210       return false;
    211     }
    212   }
    213   auto returnType = usedefs_.FindDef(entryPoint.second.type_id);
    214   if (!returnType.first || SpvOpTypeVoid != returnType.second.opcode) {
    215     DIAG(entryPointIndex) << "OpEntryPoint Entry Point <id> '"
    216                           << inst->words[entryPointIndex]
    217                           << "'s function return type is not void.";
    218     return false;
    219   }
    220   return true;
    221 }
    222 
    223 template <>
    224 bool idUsage::isValid<SpvOpExecutionMode>(const spv_instruction_t* inst,
    225                                           const spv_opcode_desc) {
    226   auto entryPointIndex = 1;
    227   auto entryPointID = inst->words[entryPointIndex];
    228   auto found =
    229       std::find(entry_points_.cbegin(), entry_points_.cend(), entryPointID);
    230   if (found == entry_points_.cend()) {
    231     DIAG(entryPointIndex) << "OpExecutionMode Entry Point <id> '"
    232                           << inst->words[entryPointIndex]
    233                           << "' is not the Entry Point "
    234                              "operand of an OpEntryPoint.";
    235     return false;
    236   }
    237   return true;
    238 }
    239 
    240 template <>
    241 bool idUsage::isValid<SpvOpTypeVector>(const spv_instruction_t* inst,
    242                                        const spv_opcode_desc) {
    243   auto componentIndex = 2;
    244   auto componentType = usedefs_.FindDef(inst->words[componentIndex]);
    245   if (!componentType.first ||
    246       !spvOpcodeIsScalarType(componentType.second.opcode)) {
    247     DIAG(componentIndex) << "OpTypeVector Component Type <id> '"
    248                          << inst->words[componentIndex]
    249                          << "' is not a scalar type.";
    250     return false;
    251   }
    252   return true;
    253 }
    254 
    255 template <>
    256 bool idUsage::isValid<SpvOpTypeMatrix>(const spv_instruction_t* inst,
    257                                        const spv_opcode_desc) {
    258   auto columnTypeIndex = 2;
    259   auto columnType = usedefs_.FindDef(inst->words[columnTypeIndex]);
    260   if (!columnType.first || SpvOpTypeVector != columnType.second.opcode) {
    261     DIAG(columnTypeIndex) << "OpTypeMatrix Column Type <id> '"
    262                           << inst->words[columnTypeIndex]
    263                           << "' is not a vector.";
    264     return false;
    265   }
    266   return true;
    267 }
    268 
    269 template <>
    270 bool idUsage::isValid<SpvOpTypeSampler>(const spv_instruction_t*,
    271                                         const spv_opcode_desc) {
    272   // OpTypeSampler takes no arguments in Rev31 and beyond.
    273   return true;
    274 }
    275 
    276 // True if the integer constant is > 0. constWords are words of the
    277 // constant-defining instruction (either OpConstant or
    278 // OpSpecConstant). typeWords are the words of the constant's-type-defining
    279 // OpTypeInt.
    280 bool aboveZero(const std::vector<uint32_t>& constWords,
    281                const std::vector<uint32_t>& typeWords) {
    282   const uint32_t width = typeWords[2];
    283   const bool is_signed = typeWords[3] > 0;
    284   const uint32_t loWord = constWords[3];
    285   if (width > 32) {
    286     // The spec currently doesn't allow integers wider than 64 bits.
    287     const uint32_t hiWord = constWords[4];  // Must exist, per spec.
    288     if (is_signed && (hiWord >> 31)) return false;
    289     return (loWord | hiWord) > 0;
    290   } else {
    291     if (is_signed && (loWord >> 31)) return false;
    292     return loWord > 0;
    293   }
    294 }
    295 
    296 template <>
    297 bool idUsage::isValid<SpvOpTypeArray>(const spv_instruction_t* inst,
    298                                       const spv_opcode_desc) {
    299   auto elementTypeIndex = 2;
    300   auto elementType = usedefs_.FindDef(inst->words[elementTypeIndex]);
    301   if (!elementType.first ||
    302       !spvOpcodeGeneratesType(elementType.second.opcode)) {
    303     DIAG(elementTypeIndex) << "OpTypeArray Element Type <id> '"
    304                            << inst->words[elementTypeIndex]
    305                            << "' is not a type.";
    306     return false;
    307   }
    308   auto lengthIndex = 3;
    309   auto length = usedefs_.FindDef(inst->words[lengthIndex]);
    310   if (!length.first || !spvOpcodeIsConstant(length.second.opcode)) {
    311     DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
    312                       << "' is not a scalar constant type.";
    313     return false;
    314   }
    315 
    316   // NOTE: Check the initialiser value of the constant
    317   auto constInst = length.second.words;
    318   auto constResultTypeIndex = 1;
    319   auto constResultType = usedefs_.FindDef(constInst[constResultTypeIndex]);
    320   if (!constResultType.first || SpvOpTypeInt != constResultType.second.opcode) {
    321     DIAG(lengthIndex) << "OpTypeArray Length <id> '" << inst->words[lengthIndex]
    322                       << "' is not a constant integer type.";
    323     return false;
    324   }
    325 
    326   switch (length.second.opcode) {
    327     case SpvOpSpecConstant:
    328     case SpvOpConstant:
    329       if (aboveZero(length.second.words, constResultType.second.words)) break;
    330     // Else fall through!
    331     case SpvOpConstantNull: {
    332       DIAG(lengthIndex) << "OpTypeArray Length <id> '"
    333                         << inst->words[lengthIndex]
    334                         << "' default value must be at least 1.";
    335       return false;
    336     }
    337     case SpvOpSpecConstantOp:
    338       // Assume it's OK, rather than try to evaluate the operation.
    339       break;
    340     default:
    341       assert(0 && "bug in spvOpcodeIsConstant() or result type isn't int");
    342   }
    343   return true;
    344 }
    345 
    346 template <>
    347 bool idUsage::isValid<SpvOpTypeRuntimeArray>(const spv_instruction_t* inst,
    348                                              const spv_opcode_desc) {
    349   auto elementTypeIndex = 2;
    350   auto elementType = usedefs_.FindDef(inst->words[elementTypeIndex]);
    351   if (!elementType.first ||
    352       !spvOpcodeGeneratesType(elementType.second.opcode)) {
    353     DIAG(elementTypeIndex) << "OpTypeRuntimeArray Element Type <id> '"
    354                            << inst->words[elementTypeIndex]
    355                            << "' is not a type.";
    356     return false;
    357   }
    358   return true;
    359 }
    360 
    361 template <>
    362 bool idUsage::isValid<SpvOpTypeStruct>(const spv_instruction_t* inst,
    363                                        const spv_opcode_desc) {
    364   for (size_t memberTypeIndex = 2; memberTypeIndex < inst->words.size();
    365        ++memberTypeIndex) {
    366     auto memberType = usedefs_.FindDef(inst->words[memberTypeIndex]);
    367     if (!memberType.first ||
    368         !spvOpcodeGeneratesType(memberType.second.opcode)) {
    369       DIAG(memberTypeIndex) << "OpTypeStruct Member Type <id> '"
    370                             << inst->words[memberTypeIndex]
    371                             << "' is not a type.";
    372       return false;
    373     }
    374   }
    375   return true;
    376 }
    377 
    378 template <>
    379 bool idUsage::isValid<SpvOpTypePointer>(const spv_instruction_t* inst,
    380                                         const spv_opcode_desc) {
    381   auto typeIndex = 3;
    382   auto type = usedefs_.FindDef(inst->words[typeIndex]);
    383   if (!type.first || !spvOpcodeGeneratesType(type.second.opcode)) {
    384     DIAG(typeIndex) << "OpTypePointer Type <id> '" << inst->words[typeIndex]
    385                     << "' is not a type.";
    386     return false;
    387   }
    388   return true;
    389 }
    390 
    391 template <>
    392 bool idUsage::isValid<SpvOpTypeFunction>(const spv_instruction_t* inst,
    393                                          const spv_opcode_desc) {
    394   auto returnTypeIndex = 2;
    395   auto returnType = usedefs_.FindDef(inst->words[returnTypeIndex]);
    396   if (!returnType.first || !spvOpcodeGeneratesType(returnType.second.opcode)) {
    397     DIAG(returnTypeIndex) << "OpTypeFunction Return Type <id> '"
    398                           << inst->words[returnTypeIndex] << "' is not a type.";
    399     return false;
    400   }
    401   for (size_t paramTypeIndex = 3; paramTypeIndex < inst->words.size();
    402        ++paramTypeIndex) {
    403     auto paramType = usedefs_.FindDef(inst->words[paramTypeIndex]);
    404     if (!paramType.first || !spvOpcodeGeneratesType(paramType.second.opcode)) {
    405       DIAG(paramTypeIndex) << "OpTypeFunction Parameter Type <id> '"
    406                            << inst->words[paramTypeIndex] << "' is not a type.";
    407       return false;
    408     }
    409   }
    410   return true;
    411 }
    412 
    413 template <>
    414 bool idUsage::isValid<SpvOpTypePipe>(const spv_instruction_t*,
    415                                      const spv_opcode_desc) {
    416   // OpTypePipe has no ID arguments.
    417   return true;
    418 }
    419 
    420 template <>
    421 bool idUsage::isValid<SpvOpConstantTrue>(const spv_instruction_t* inst,
    422                                          const spv_opcode_desc) {
    423   auto resultTypeIndex = 1;
    424   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    425   if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) {
    426     DIAG(resultTypeIndex) << "OpConstantTrue Result Type <id> '"
    427                           << inst->words[resultTypeIndex]
    428                           << "' is not a boolean type.";
    429     return false;
    430   }
    431   return true;
    432 }
    433 
    434 template <>
    435 bool idUsage::isValid<SpvOpConstantFalse>(const spv_instruction_t* inst,
    436                                           const spv_opcode_desc) {
    437   auto resultTypeIndex = 1;
    438   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    439   if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) {
    440     DIAG(resultTypeIndex) << "OpConstantFalse Result Type <id> '"
    441                           << inst->words[resultTypeIndex]
    442                           << "' is not a boolean type.";
    443     return false;
    444   }
    445   return true;
    446 }
    447 
    448 template <>
    449 bool idUsage::isValid<SpvOpConstantComposite>(const spv_instruction_t* inst,
    450                                               const spv_opcode_desc) {
    451   auto resultTypeIndex = 1;
    452   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    453   if (!resultType.first || !spvOpcodeIsComposite(resultType.second.opcode)) {
    454     DIAG(resultTypeIndex) << "OpConstantComposite Result Type <id> '"
    455                           << inst->words[resultTypeIndex]
    456                           << "' is not a composite type.";
    457     return false;
    458   }
    459 
    460   auto constituentCount = inst->words.size() - 3;
    461   switch (resultType.second.opcode) {
    462     case SpvOpTypeVector: {
    463       auto componentCount = resultType.second.words[3];
    464       spvCheck(
    465           componentCount != constituentCount,
    466           // TODO: Output ID's on diagnostic
    467           DIAG(inst->words.size() - 1)
    468               << "OpConstantComposite Constituent <id> count does not match "
    469                  "Result Type <id> '"
    470               << resultType.second.id << "'s vector component count.";
    471           return false);
    472       auto componentType = usedefs_.FindDef(resultType.second.words[2]);
    473       assert(componentType.first);
    474       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    475            constituentIndex++) {
    476         auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
    477         if (!constituent.first ||
    478             !spvOpcodeIsConstant(constituent.second.opcode)) {
    479           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    480                                  << inst->words[constituentIndex]
    481                                  << "' is not a constant.";
    482           return false;
    483         }
    484         auto constituentResultType =
    485             usedefs_.FindDef(constituent.second.type_id);
    486         if (!constituentResultType.first ||
    487             componentType.second.opcode !=
    488                 constituentResultType.second.opcode) {
    489           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    490                                  << inst->words[constituentIndex]
    491                                  << "'s type does not match Result Type <id> '"
    492                                  << resultType.second.id
    493                                  << "'s vector element type.";
    494           return false;
    495         }
    496       }
    497     } break;
    498     case SpvOpTypeMatrix: {
    499       auto columnCount = resultType.second.words[3];
    500       spvCheck(
    501           columnCount != constituentCount,
    502           // TODO: Output ID's on diagnostic
    503           DIAG(inst->words.size() - 1)
    504               << "OpConstantComposite Constituent <id> count does not match "
    505                  "Result Type <id> '"
    506               << resultType.second.id << "'s matrix column count.";
    507           return false);
    508 
    509       auto columnType = usedefs_.FindDef(resultType.second.words[2]);
    510       assert(columnType.first);
    511       auto componentCount = columnType.second.words[3];
    512       auto componentType = usedefs_.FindDef(columnType.second.words[2]);
    513       assert(componentType.first);
    514 
    515       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    516            constituentIndex++) {
    517         auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
    518         if (!constituent.first ||
    519             SpvOpConstantComposite != constituent.second.opcode) {
    520           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    521                                  << inst->words[constituentIndex]
    522                                  << "' is not a constant composite.";
    523           return false;
    524         }
    525         auto vector = usedefs_.FindDef(constituent.second.type_id);
    526         assert(vector.first);
    527         spvCheck(columnType.second.opcode != vector.second.opcode,
    528                  DIAG(constituentIndex)
    529                      << "OpConstantComposite Constituent <id> '"
    530                      << inst->words[constituentIndex]
    531                      << "' type does not match Result Type <id> '"
    532                      << resultType.second.id << "'s matrix column type.";
    533                  return false);
    534         auto vectorComponentType = usedefs_.FindDef(vector.second.words[2]);
    535         assert(vectorComponentType.first);
    536         spvCheck(componentType.second.id != vectorComponentType.second.id,
    537                  DIAG(constituentIndex)
    538                      << "OpConstantComposite Constituent <id> '"
    539                      << inst->words[constituentIndex]
    540                      << "' component type does not match Result Type <id> '"
    541                      << resultType.second.id
    542                      << "'s matrix column component type.";
    543                  return false);
    544         spvCheck(
    545             componentCount != vector.second.words[3],
    546             DIAG(constituentIndex)
    547                 << "OpConstantComposite Constituent <id> '"
    548                 << inst->words[constituentIndex]
    549                 << "' vector component count does not match Result Type <id> '"
    550                 << resultType.second.id << "'s vector component count.";
    551             return false);
    552       }
    553     } break;
    554     case SpvOpTypeArray: {
    555       auto elementType = usedefs_.FindDef(resultType.second.words[2]);
    556       assert(elementType.first);
    557       auto length = usedefs_.FindDef(resultType.second.words[3]);
    558       assert(length.first);
    559       spvCheck(length.second.words[3] != constituentCount,
    560                DIAG(inst->words.size() - 1)
    561                    << "OpConstantComposite Constituent count does not match "
    562                       "Result Type <id> '"
    563                    << resultType.second.id << "'s array length.";
    564                return false);
    565       for (size_t constituentIndex = 3; constituentIndex < inst->words.size();
    566            constituentIndex++) {
    567         auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
    568         if (!constituent.first ||
    569             !spvOpcodeIsConstant(constituent.second.opcode)) {
    570           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    571                                  << inst->words[constituentIndex]
    572                                  << "' is not a constant.";
    573           return false;
    574         }
    575         auto constituentType = usedefs_.FindDef(constituent.second.type_id);
    576         assert(constituentType.first);
    577         spvCheck(elementType.second.id != constituentType.second.id,
    578                  DIAG(constituentIndex)
    579                      << "OpConstantComposite Constituent <id> '"
    580                      << inst->words[constituentIndex]
    581                      << "'s type does not match Result Type <id> '"
    582                      << resultType.second.id << "'s array element type.";
    583                  return false);
    584       }
    585     } break;
    586     case SpvOpTypeStruct: {
    587       auto memberCount = resultType.second.words.size() - 2;
    588       spvCheck(memberCount != constituentCount,
    589                DIAG(resultTypeIndex)
    590                    << "OpConstantComposite Constituent <id> '"
    591                    << inst->words[resultTypeIndex]
    592                    << "' count does not match Result Type <id> '"
    593                    << resultType.second.id << "'s struct member count.";
    594                return false);
    595       for (uint32_t constituentIndex = 3, memberIndex = 2;
    596            constituentIndex < inst->words.size();
    597            constituentIndex++, memberIndex++) {
    598         auto constituent = usedefs_.FindDef(inst->words[constituentIndex]);
    599         if (!constituent.first ||
    600             !spvOpcodeIsConstant(constituent.second.opcode)) {
    601           DIAG(constituentIndex) << "OpConstantComposite Constituent <id> '"
    602                                  << inst->words[constituentIndex]
    603                                  << "' is not a constant.";
    604           return false;
    605         }
    606         auto constituentType = usedefs_.FindDef(constituent.second.type_id);
    607         assert(constituentType.first);
    608 
    609         auto memberType =
    610             usedefs_.FindDef(resultType.second.words[memberIndex]);
    611         assert(memberType.first);
    612         spvCheck(memberType.second.id != constituentType.second.id,
    613                  DIAG(constituentIndex)
    614                      << "OpConstantComposite Constituent <id> '"
    615                      << inst->words[constituentIndex]
    616                      << "' type does not match the Result Type <id> '"
    617                      << resultType.second.id << "'s member type.";
    618                  return false);
    619       }
    620     } break;
    621     default: { assert(0 && "Unreachable!"); } break;
    622   }
    623   return true;
    624 }
    625 
    626 template <>
    627 bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
    628                                             const spv_opcode_desc) {
    629   auto resultTypeIndex = 1;
    630   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    631   if (!resultType.first || SpvOpTypeSampler != resultType.second.opcode) {
    632     DIAG(resultTypeIndex) << "OpConstantSampler Result Type <id> '"
    633                           << inst->words[resultTypeIndex]
    634                           << "' is not a sampler type.";
    635     return false;
    636   }
    637   return true;
    638 }
    639 
    640 // True if instruction defines a type that can have a null value, as defined by
    641 // the SPIR-V spec.  Tracks composite-type components through usedefs to check
    642 // nullability transitively.
    643 bool IsTypeNullable(const std::vector<uint32_t>& instruction,
    644                     const UseDefTracker& usedefs) {
    645   uint16_t opcode;
    646   uint16_t word_count;
    647   spvOpcodeSplit(instruction[0], &word_count, &opcode);
    648   switch (static_cast<SpvOp>(opcode)) {
    649     case SpvOpTypeBool:
    650     case SpvOpTypeInt:
    651     case SpvOpTypeFloat:
    652     case SpvOpTypePointer:
    653     case SpvOpTypeEvent:
    654     case SpvOpTypeDeviceEvent:
    655     case SpvOpTypeReserveId:
    656     case SpvOpTypeQueue:
    657       return true;
    658     case SpvOpTypeArray:
    659     case SpvOpTypeMatrix:
    660     case SpvOpTypeVector: {
    661       auto base_type = usedefs.FindDef(instruction[2]);
    662       return base_type.first && IsTypeNullable(base_type.second.words, usedefs);
    663     }
    664     case SpvOpTypeStruct: {
    665       for (size_t elementIndex = 2; elementIndex < instruction.size();
    666            ++elementIndex) {
    667         auto element = usedefs.FindDef(instruction[elementIndex]);
    668         if (!element.first || !IsTypeNullable(element.second.words, usedefs))
    669           return false;
    670       }
    671       return true;
    672     }
    673     default:
    674       return false;
    675   }
    676 }
    677 
    678 template <>
    679 bool idUsage::isValid<SpvOpConstantNull>(const spv_instruction_t* inst,
    680                                          const spv_opcode_desc) {
    681   auto resultTypeIndex = 1;
    682   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    683   if (!resultType.first || !IsTypeNullable(resultType.second.words, usedefs_)) {
    684     DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
    685                           << inst->words[resultTypeIndex]
    686                           << "' cannot have a null value.";
    687     return false;
    688   }
    689   return true;
    690 }
    691 
    692 template <>
    693 bool idUsage::isValid<SpvOpSpecConstantTrue>(const spv_instruction_t* inst,
    694                                              const spv_opcode_desc) {
    695   auto resultTypeIndex = 1;
    696   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    697   if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) {
    698     DIAG(resultTypeIndex) << "OpSpecConstantTrue Result Type <id> '"
    699                           << inst->words[resultTypeIndex]
    700                           << "' is not a boolean type.";
    701     return false;
    702   }
    703   return true;
    704 }
    705 
    706 template <>
    707 bool idUsage::isValid<SpvOpSpecConstantFalse>(const spv_instruction_t* inst,
    708                                               const spv_opcode_desc) {
    709   auto resultTypeIndex = 1;
    710   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    711   if (!resultType.first || SpvOpTypeBool != resultType.second.opcode) {
    712     DIAG(resultTypeIndex) << "OpSpecConstantFalse Result Type <id> '"
    713                           << inst->words[resultTypeIndex]
    714                           << "' is not a boolean type.";
    715     return false;
    716   }
    717   return true;
    718 }
    719 
    720 #if 0
    721 template <>
    722 bool idUsage::isValid<SpvOpSpecConstantComposite>(
    723     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
    724 #endif
    725 
    726 #if 0
    727 template <>
    728 bool idUsage::isValid<SpvOpSpecConstantOp>(const spv_instruction_t *inst) {}
    729 #endif
    730 
    731 template <>
    732 bool idUsage::isValid<SpvOpVariable>(const spv_instruction_t* inst,
    733                                      const spv_opcode_desc opcodeEntry) {
    734   auto resultTypeIndex = 1;
    735   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    736   if (!resultType.first || SpvOpTypePointer != resultType.second.opcode) {
    737     DIAG(resultTypeIndex) << "OpVariable Result Type <id> '"
    738                           << inst->words[resultTypeIndex]
    739                           << "' is not a pointer type.";
    740     return false;
    741   }
    742   if (opcodeEntry->numTypes < inst->words.size()) {
    743     auto initialiserIndex = 4;
    744     auto initialiser = usedefs_.FindDef(inst->words[initialiserIndex]);
    745     if (!initialiser.first || !spvOpcodeIsConstant(initialiser.second.opcode)) {
    746       DIAG(initialiserIndex) << "OpVariable Initializer <id> '"
    747                              << inst->words[initialiserIndex]
    748                              << "' is not a constant.";
    749       return false;
    750     }
    751   }
    752   return true;
    753 }
    754 
    755 template <>
    756 bool idUsage::isValid<SpvOpLoad>(const spv_instruction_t* inst,
    757                                  const spv_opcode_desc) {
    758   auto resultTypeIndex = 1;
    759   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    760   spvCheck(!resultType.first, DIAG(resultTypeIndex)
    761                                   << "OpLoad Result Type <id> '"
    762                                   << inst->words[resultTypeIndex]
    763                                   << "' is not defind.";
    764            return false);
    765   auto pointerIndex = 3;
    766   auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
    767   if (!pointer.first ||
    768       (addressingModel == SpvAddressingModelLogical &&
    769        !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
    770     DIAG(pointerIndex) << "OpLoad Pointer <id> '" << inst->words[pointerIndex]
    771                        << "' is not a pointer.";
    772     return false;
    773   }
    774   auto pointerType = usedefs_.FindDef(pointer.second.type_id);
    775   if (!pointerType.first || pointerType.second.opcode != SpvOpTypePointer) {
    776     DIAG(pointerIndex) << "OpLoad type for pointer <id> '"
    777                        << inst->words[pointerIndex]
    778                        << "' is not a pointer type.";
    779     return false;
    780   }
    781   auto pointeeType = usedefs_.FindDef(pointerType.second.words[3]);
    782   if (!pointeeType.first || resultType.second.id != pointeeType.second.id) {
    783     DIAG(resultTypeIndex) << "OpLoad Result Type <id> '"
    784                           << inst->words[resultTypeIndex]
    785                           << "' does not match Pointer <id> '"
    786                           << pointer.second.id << "'s type.";
    787     return false;
    788   }
    789   return true;
    790 }
    791 
    792 template <>
    793 bool idUsage::isValid<SpvOpStore>(const spv_instruction_t* inst,
    794                                   const spv_opcode_desc) {
    795   auto pointerIndex = 1;
    796   auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
    797   if (!pointer.first ||
    798       (addressingModel == SpvAddressingModelLogical &&
    799        !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
    800     DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
    801                        << "' is not a pointer.";
    802     return false;
    803   }
    804   auto pointerType = usedefs_.FindDef(pointer.second.type_id);
    805   if (!pointer.first || pointerType.second.opcode != SpvOpTypePointer) {
    806     DIAG(pointerIndex) << "OpStore type for pointer <id> '"
    807                        << inst->words[pointerIndex]
    808                        << "' is not a pointer type.";
    809     return false;
    810   }
    811   auto type = usedefs_.FindDef(pointerType.second.words[3]);
    812   assert(type.first);
    813   spvCheck(SpvOpTypeVoid == type.second.opcode, DIAG(pointerIndex)
    814                                                     << "OpStore Pointer <id> '"
    815                                                     << inst->words[pointerIndex]
    816                                                     << "'s type is void.";
    817            return false);
    818 
    819   auto objectIndex = 2;
    820   auto object = usedefs_.FindDef(inst->words[objectIndex]);
    821   if (!object.first || !object.second.type_id) {
    822     DIAG(objectIndex) << "OpStore Object <id> '" << inst->words[objectIndex]
    823                       << "' is not an object.";
    824     return false;
    825   }
    826   auto objectType = usedefs_.FindDef(object.second.type_id);
    827   assert(objectType.first);
    828   spvCheck(SpvOpTypeVoid == objectType.second.opcode,
    829            DIAG(objectIndex) << "OpStore Object <id> '"
    830                              << inst->words[objectIndex] << "'s type is void.";
    831            return false);
    832 
    833   spvCheck(type.second.id != objectType.second.id,
    834            DIAG(pointerIndex)
    835                << "OpStore Pointer <id> '" << inst->words[pointerIndex]
    836                << "'s type does not match Object <id> '" << objectType.second.id
    837                << "'s type.";
    838            return false);
    839   return true;
    840 }
    841 
    842 template <>
    843 bool idUsage::isValid<SpvOpCopyMemory>(const spv_instruction_t* inst,
    844                                        const spv_opcode_desc) {
    845   auto targetIndex = 1;
    846   auto target = usedefs_.FindDef(inst->words[targetIndex]);
    847   if (!target.first) return false;
    848   auto sourceIndex = 2;
    849   auto source = usedefs_.FindDef(inst->words[sourceIndex]);
    850   if (!source.first) return false;
    851   auto targetPointerType = usedefs_.FindDef(target.second.type_id);
    852   assert(targetPointerType.first);
    853   auto targetType = usedefs_.FindDef(targetPointerType.second.words[3]);
    854   assert(targetType.first);
    855   auto sourcePointerType = usedefs_.FindDef(source.second.type_id);
    856   assert(sourcePointerType.first);
    857   auto sourceType = usedefs_.FindDef(sourcePointerType.second.words[3]);
    858   assert(sourceType.first);
    859   spvCheck(targetType.second.id != sourceType.second.id,
    860            DIAG(sourceIndex)
    861                << "OpCopyMemory Target <id> '" << inst->words[sourceIndex]
    862                << "'s type does not match Source <id> '" << sourceType.second.id
    863                << "'s type.";
    864            return false);
    865   return true;
    866 }
    867 
    868 template <>
    869 bool idUsage::isValid<SpvOpCopyMemorySized>(const spv_instruction_t* inst,
    870                                             const spv_opcode_desc) {
    871   auto targetIndex = 1;
    872   auto target = usedefs_.FindDef(inst->words[targetIndex]);
    873   if (!target.first) return false;
    874   auto sourceIndex = 2;
    875   auto source = usedefs_.FindDef(inst->words[sourceIndex]);
    876   if (!source.first) return false;
    877   auto sizeIndex = 3;
    878   auto size = usedefs_.FindDef(inst->words[sizeIndex]);
    879   if (!size.first) return false;
    880   auto targetPointerType = usedefs_.FindDef(target.second.type_id);
    881   spvCheck(!targetPointerType.first ||
    882                SpvOpTypePointer != targetPointerType.second.opcode,
    883            DIAG(targetIndex) << "OpCopyMemorySized Target <id> '"
    884                              << inst->words[targetIndex]
    885                              << "' is not a pointer.";
    886            return false);
    887   auto sourcePointerType = usedefs_.FindDef(source.second.type_id);
    888   spvCheck(!sourcePointerType.first ||
    889                SpvOpTypePointer != sourcePointerType.second.opcode,
    890            DIAG(sourceIndex) << "OpCopyMemorySized Source <id> '"
    891                              << inst->words[sourceIndex]
    892                              << "' is not a pointer.";
    893            return false);
    894   switch (size.second.opcode) {
    895     // TODO: The following opcode's are assumed to be valid, refer to the
    896     // following bug https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13871 for
    897     // clarification
    898     case SpvOpConstant:
    899     case SpvOpSpecConstant: {
    900       auto sizeType = usedefs_.FindDef(size.second.type_id);
    901       assert(sizeType.first);
    902       spvCheck(SpvOpTypeInt != sizeType.second.opcode,
    903                DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
    904                                << inst->words[sizeIndex]
    905                                << "'s type is not an integer type.";
    906                return false);
    907     } break;
    908     case SpvOpVariable: {
    909       auto pointerType = usedefs_.FindDef(size.second.type_id);
    910       assert(pointerType.first);
    911       auto sizeType = usedefs_.FindDef(pointerType.second.type_id);
    912       spvCheck(!sizeType.first || SpvOpTypeInt != sizeType.second.opcode,
    913                DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
    914                                << inst->words[sizeIndex]
    915                                << "'s variable type is not an integer type.";
    916                return false);
    917     } break;
    918     default:
    919       DIAG(sizeIndex) << "OpCopyMemorySized Size <id> '"
    920                       << inst->words[sizeIndex]
    921                       << "' is not a constant or variable.";
    922       return false;
    923   }
    924   // TODO: Check that consant is a least size 1, see the same bug as above for
    925   // clarification?
    926   return true;
    927 }
    928 
    929 #if 0
    930 template <>
    931 bool idUsage::isValid<SpvOpAccessChain>(const spv_instruction_t *inst,
    932                                         const spv_opcode_desc opcodeEntry) {}
    933 #endif
    934 
    935 #if 0
    936 template <>
    937 bool idUsage::isValid<SpvOpInBoundsAccessChain>(
    938     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
    939 #endif
    940 
    941 #if 0
    942 template <>
    943 bool idUsage::isValid<SpvOpArrayLength>(const spv_instruction_t *inst,
    944                                         const spv_opcode_desc opcodeEntry) {}
    945 #endif
    946 
    947 #if 0
    948 template <>
    949 bool idUsage::isValid<SpvOpImagePointer>(const spv_instruction_t *inst,
    950                                          const spv_opcode_desc opcodeEntry) {}
    951 #endif
    952 
    953 #if 0
    954 template <>
    955 bool idUsage::isValid<SpvOpGenericPtrMemSemantics>(
    956     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
    957 #endif
    958 
    959 template <>
    960 bool idUsage::isValid<SpvOpFunction>(const spv_instruction_t* inst,
    961                                      const spv_opcode_desc) {
    962   auto resultTypeIndex = 1;
    963   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    964   if (!resultType.first) return false;
    965   auto functionTypeIndex = 4;
    966   auto functionType = usedefs_.FindDef(inst->words[functionTypeIndex]);
    967   if (!functionType.first || SpvOpTypeFunction != functionType.second.opcode) {
    968     DIAG(functionTypeIndex) << "OpFunction Function Type <id> '"
    969                             << inst->words[functionTypeIndex]
    970                             << "' is not a function type.";
    971     return false;
    972   }
    973   auto returnType = usedefs_.FindDef(functionType.second.words[2]);
    974   assert(returnType.first);
    975   spvCheck(returnType.second.id != resultType.second.id,
    976            DIAG(resultTypeIndex) << "OpFunction Result Type <id> '"
    977                                  << inst->words[resultTypeIndex]
    978                                  << "' does not match the Function Type <id> '"
    979                                  << resultType.second.id << "'s return type.";
    980            return false);
    981   return true;
    982 }
    983 
    984 template <>
    985 bool idUsage::isValid<SpvOpFunctionParameter>(const spv_instruction_t* inst,
    986                                               const spv_opcode_desc) {
    987   auto resultTypeIndex = 1;
    988   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
    989   if (!resultType.first) return false;
    990   // NOTE: Find OpFunction & ensure OpFunctionParameter is not out of place.
    991   size_t paramIndex = 0;
    992   assert(firstInst < inst && "Invalid instruction pointer");
    993   while (firstInst != --inst) {
    994     if (SpvOpFunction == inst->opcode) {
    995       break;
    996     } else if (SpvOpFunctionParameter == inst->opcode) {
    997       paramIndex++;
    998     }
    999   }
   1000   auto functionType = usedefs_.FindDef(inst->words[4]);
   1001   assert(functionType.first);
   1002   if (paramIndex >= functionType.second.words.size() - 3) {
   1003     DIAG(0) << "Too many OpFunctionParameters for " << inst->words[2]
   1004             << ": expected " << functionType.second.words.size() - 3
   1005             << " based on the function's type";
   1006     return false;
   1007   }
   1008   auto paramType = usedefs_.FindDef(functionType.second.words[paramIndex + 3]);
   1009   assert(paramType.first);
   1010   spvCheck(resultType.second.id != paramType.second.id,
   1011            DIAG(resultTypeIndex)
   1012                << "OpFunctionParameter Result Type <id> '"
   1013                << inst->words[resultTypeIndex]
   1014                << "' does not match the OpTypeFunction parameter "
   1015                   "type of the same index.";
   1016            return false);
   1017   return true;
   1018 }
   1019 
   1020 template <>
   1021 bool idUsage::isValid<SpvOpFunctionCall>(const spv_instruction_t* inst,
   1022                                          const spv_opcode_desc) {
   1023   auto resultTypeIndex = 1;
   1024   auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
   1025   if (!resultType.first) return false;
   1026   auto functionIndex = 3;
   1027   auto function = usedefs_.FindDef(inst->words[functionIndex]);
   1028   if (!function.first || SpvOpFunction != function.second.opcode) {
   1029     DIAG(functionIndex) << "OpFunctionCall Function <id> '"
   1030                         << inst->words[functionIndex] << "' is not a function.";
   1031     return false;
   1032   }
   1033   auto returnType = usedefs_.FindDef(function.second.type_id);
   1034   assert(returnType.first);
   1035   spvCheck(returnType.second.id != resultType.second.id,
   1036            DIAG(resultTypeIndex) << "OpFunctionCall Result Type <id> '"
   1037                                  << inst->words[resultTypeIndex]
   1038                                  << "'s type does not match Function <id> '"
   1039                                  << returnType.second.id << "'s return type.";
   1040            return false);
   1041   auto functionType = usedefs_.FindDef(function.second.words[4]);
   1042   assert(functionType.first);
   1043   auto functionCallArgCount = inst->words.size() - 4;
   1044   auto functionParamCount = functionType.second.words.size() - 3;
   1045   spvCheck(
   1046       functionParamCount != functionCallArgCount,
   1047       DIAG(inst->words.size() - 1)
   1048           << "OpFunctionCall Function <id>'s parameter count does not match "
   1049              "the argument count.";
   1050       return false);
   1051   for (size_t argumentIndex = 4, paramIndex = 3;
   1052        argumentIndex < inst->words.size(); argumentIndex++, paramIndex++) {
   1053     auto argument = usedefs_.FindDef(inst->words[argumentIndex]);
   1054     if (!argument.first) return false;
   1055     auto argumentType = usedefs_.FindDef(argument.second.type_id);
   1056     assert(argumentType.first);
   1057     auto parameterType =
   1058         usedefs_.FindDef(functionType.second.words[paramIndex]);
   1059     assert(parameterType.first);
   1060     spvCheck(argumentType.second.id != parameterType.second.id,
   1061              DIAG(argumentIndex) << "OpFunctionCall Argument <id> '"
   1062                                  << inst->words[argumentIndex]
   1063                                  << "'s type does not match Function <id> '"
   1064                                  << parameterType.second.id
   1065                                  << "'s parameter type.";
   1066              return false);
   1067   }
   1068   return true;
   1069 }
   1070 
   1071 #if 0
   1072 template <>
   1073 bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
   1074                                      const spv_opcode_desc opcodeEntry) {}
   1075 #endif
   1076 
   1077 #if 0
   1078 template <>
   1079 bool idUsage::isValid<OpConvertFToS>(const spv_instruction_t *inst,
   1080                                      const spv_opcode_desc opcodeEntry) {}
   1081 #endif
   1082 
   1083 #if 0
   1084 template <>
   1085 bool idUsage::isValid<OpConvertSToF>(const spv_instruction_t *inst,
   1086                                      const spv_opcode_desc opcodeEntry) {}
   1087 #endif
   1088 
   1089 #if 0
   1090 template <>
   1091 bool idUsage::isValid<OpConvertUToF>(const spv_instruction_t *inst,
   1092                                      const spv_opcode_desc opcodeEntry) {}
   1093 #endif
   1094 
   1095 #if 0
   1096 template <>
   1097 bool idUsage::isValid<OpUConvert>(const spv_instruction_t *inst,
   1098                                   const spv_opcode_desc opcodeEntry) {}
   1099 #endif
   1100 
   1101 #if 0
   1102 template <>
   1103 bool idUsage::isValid<OpSConvert>(const spv_instruction_t *inst,
   1104                                   const spv_opcode_desc opcodeEntry) {}
   1105 #endif
   1106 
   1107 #if 0
   1108 template <>
   1109 bool idUsage::isValid<OpFConvert>(const spv_instruction_t *inst,
   1110                                   const spv_opcode_desc opcodeEntry) {}
   1111 #endif
   1112 
   1113 #if 0
   1114 template <>
   1115 bool idUsage::isValid<OpConvertPtrToU>(const spv_instruction_t *inst,
   1116                                        const spv_opcode_desc opcodeEntry) {
   1117 }
   1118 #endif
   1119 
   1120 #if 0
   1121 template <>
   1122 bool idUsage::isValid<OpConvertUToPtr>(const spv_instruction_t *inst,
   1123                                        const spv_opcode_desc opcodeEntry) {
   1124 }
   1125 #endif
   1126 
   1127 #if 0
   1128 template <>
   1129 bool idUsage::isValid<OpPtrCastToGeneric>(
   1130     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1131 #endif
   1132 
   1133 #if 0
   1134 template <>
   1135 bool idUsage::isValid<OpGenericCastToPtr>(
   1136     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1137 #endif
   1138 
   1139 #if 0
   1140 template <>
   1141 bool idUsage::isValid<OpBitcast>(const spv_instruction_t *inst,
   1142                                  const spv_opcode_desc opcodeEntry) {}
   1143 #endif
   1144 
   1145 #if 0
   1146 template <>
   1147 bool idUsage::isValid<OpGenericCastToPtrExplicit>(
   1148     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1149 #endif
   1150 
   1151 #if 0
   1152 template <>
   1153 bool idUsage::isValid<OpSatConvertSToU>(const spv_instruction_t *inst) {}
   1154 #endif
   1155 
   1156 #if 0
   1157 template <>
   1158 bool idUsage::isValid<OpSatConvertUToS>(const spv_instruction_t *inst) {}
   1159 #endif
   1160 
   1161 #if 0
   1162 template <>
   1163 bool idUsage::isValid<OpVectorExtractDynamic>(
   1164     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1165 #endif
   1166 
   1167 #if 0
   1168 template <>
   1169 bool idUsage::isValid<OpVectorInsertDynamic>(
   1170     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1171 #endif
   1172 
   1173 #if 0
   1174 template <>
   1175 bool idUsage::isValid<OpVectorShuffle>(const spv_instruction_t *inst,
   1176                                        const spv_opcode_desc opcodeEntry) {
   1177 }
   1178 #endif
   1179 
   1180 #if 0
   1181 template <>
   1182 bool idUsage::isValid<OpCompositeConstruct>(
   1183     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1184 #endif
   1185 
   1186 #if 0
   1187 template <>
   1188 bool idUsage::isValid<OpCompositeExtract>(
   1189     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1190 #endif
   1191 
   1192 #if 0
   1193 template <>
   1194 bool idUsage::isValid<OpCompositeInsert>(
   1195     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1196 #endif
   1197 
   1198 #if 0
   1199 template <>
   1200 bool idUsage::isValid<OpCopyObject>(const spv_instruction_t *inst,
   1201                                     const spv_opcode_desc opcodeEntry) {}
   1202 #endif
   1203 
   1204 #if 0
   1205 template <>
   1206 bool idUsage::isValid<OpTranspose>(const spv_instruction_t *inst,
   1207                                    const spv_opcode_desc opcodeEntry) {}
   1208 #endif
   1209 
   1210 #if 0
   1211 template <>
   1212 bool idUsage::isValid<OpSNegate>(const spv_instruction_t *inst,
   1213                                  const spv_opcode_desc opcodeEntry) {}
   1214 #endif
   1215 
   1216 #if 0
   1217 template <>
   1218 bool idUsage::isValid<OpFNegate>(const spv_instruction_t *inst,
   1219                                  const spv_opcode_desc opcodeEntry) {}
   1220 #endif
   1221 
   1222 #if 0
   1223 template <>
   1224 bool idUsage::isValid<OpNot>(const spv_instruction_t *inst,
   1225                              const spv_opcode_desc opcodeEntry) {}
   1226 #endif
   1227 
   1228 #if 0
   1229 template <>
   1230 bool idUsage::isValid<OpIAdd>(const spv_instruction_t *inst,
   1231                               const spv_opcode_desc opcodeEntry) {}
   1232 #endif
   1233 
   1234 #if 0
   1235 template <>
   1236 bool idUsage::isValid<OpFAdd>(const spv_instruction_t *inst,
   1237                               const spv_opcode_desc opcodeEntry) {}
   1238 #endif
   1239 
   1240 #if 0
   1241 template <>
   1242 bool idUsage::isValid<OpISub>(const spv_instruction_t *inst,
   1243                               const spv_opcode_desc opcodeEntry) {}
   1244 #endif
   1245 
   1246 #if 0
   1247 template <>
   1248 bool idUsage::isValid<OpFSub>(const spv_instruction_t *inst,
   1249                               const spv_opcode_desc opcodeEntry) {}
   1250 #endif
   1251 
   1252 #if 0
   1253 template <>
   1254 bool idUsage::isValid<OpIMul>(const spv_instruction_t *inst,
   1255                               const spv_opcode_desc opcodeEntry) {}
   1256 #endif
   1257 
   1258 #if 0
   1259 template <>
   1260 bool idUsage::isValid<OpFMul>(const spv_instruction_t *inst,
   1261                               const spv_opcode_desc opcodeEntry) {}
   1262 #endif
   1263 
   1264 #if 0
   1265 template <>
   1266 bool idUsage::isValid<OpUDiv>(const spv_instruction_t *inst,
   1267                               const spv_opcode_desc opcodeEntry) {}
   1268 #endif
   1269 
   1270 #if 0
   1271 template <>
   1272 bool idUsage::isValid<OpSDiv>(const spv_instruction_t *inst,
   1273                               const spv_opcode_desc opcodeEntry) {}
   1274 #endif
   1275 
   1276 #if 0
   1277 template <>
   1278 bool idUsage::isValid<OpFDiv>(const spv_instruction_t *inst,
   1279                               const spv_opcode_desc opcodeEntry) {}
   1280 #endif
   1281 
   1282 #if 0
   1283 template <>
   1284 bool idUsage::isValid<OpUMod>(const spv_instruction_t *inst,
   1285                               const spv_opcode_desc opcodeEntry) {}
   1286 #endif
   1287 
   1288 #if 0
   1289 template <>
   1290 bool idUsage::isValid<OpSRem>(const spv_instruction_t *inst,
   1291                               const spv_opcode_desc opcodeEntry) {}
   1292 #endif
   1293 
   1294 #if 0
   1295 template <>
   1296 bool idUsage::isValid<OpSMod>(const spv_instruction_t *inst,
   1297                               const spv_opcode_desc opcodeEntry) {}
   1298 #endif
   1299 
   1300 #if 0
   1301 template <>
   1302 bool idUsage::isValid<OpFRem>(const spv_instruction_t *inst,
   1303                               const spv_opcode_desc opcodeEntry) {}
   1304 #endif
   1305 
   1306 #if 0
   1307 template <>
   1308 bool idUsage::isValid<OpFMod>(const spv_instruction_t *inst,
   1309                               const spv_opcode_desc opcodeEntry) {}
   1310 #endif
   1311 
   1312 #if 0
   1313 template <>
   1314 bool idUsage::isValid<OpVectorTimesScalar>(
   1315     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1316 #endif
   1317 
   1318 #if 0
   1319 template <>
   1320 bool idUsage::isValid<OpMatrixTimesScalar>(
   1321     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1322 #endif
   1323 
   1324 #if 0
   1325 template <>
   1326 bool idUsage::isValid<OpVectorTimesMatrix>(
   1327     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1328 #endif
   1329 
   1330 #if 0
   1331 template <>
   1332 bool idUsage::isValid<OpMatrixTimesVector>(
   1333     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1334 #endif
   1335 
   1336 #if 0
   1337 template <>
   1338 bool idUsage::isValid<OpMatrixTimesMatrix>(
   1339     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1340 #endif
   1341 
   1342 #if 0
   1343 template <>
   1344 bool idUsage::isValid<OpOuterProduct>(const spv_instruction_t *inst,
   1345                                       const spv_opcode_desc opcodeEntry) {}
   1346 #endif
   1347 
   1348 #if 0
   1349 template <>
   1350 bool idUsage::isValid<OpDot>(const spv_instruction_t *inst,
   1351                              const spv_opcode_desc opcodeEntry) {}
   1352 #endif
   1353 
   1354 #if 0
   1355 template <>
   1356 bool idUsage::isValid<OpShiftRightLogical>(
   1357     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1358 #endif
   1359 
   1360 #if 0
   1361 template <>
   1362 bool idUsage::isValid<OpShiftRightArithmetic>(
   1363     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1364 #endif
   1365 
   1366 #if 0
   1367 template <>
   1368 bool idUsage::isValid<OpShiftLeftLogical>(
   1369     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1370 #endif
   1371 
   1372 #if 0
   1373 template <>
   1374 bool idUsage::isValid<OpBitwiseOr>(const spv_instruction_t *inst,
   1375                                    const spv_opcode_desc opcodeEntry) {}
   1376 #endif
   1377 
   1378 #if 0
   1379 template <>
   1380 bool idUsage::isValid<OpBitwiseXor>(const spv_instruction_t *inst,
   1381                                     const spv_opcode_desc opcodeEntry) {}
   1382 #endif
   1383 
   1384 #if 0
   1385 template <>
   1386 bool idUsage::isValid<OpBitwiseAnd>(const spv_instruction_t *inst,
   1387                                     const spv_opcode_desc opcodeEntry) {}
   1388 #endif
   1389 
   1390 #if 0
   1391 template <>
   1392 bool idUsage::isValid<OpAny>(const spv_instruction_t *inst,
   1393                              const spv_opcode_desc opcodeEntry) {}
   1394 #endif
   1395 
   1396 #if 0
   1397 template <>
   1398 bool idUsage::isValid<OpAll>(const spv_instruction_t *inst,
   1399                              const spv_opcode_desc opcodeEntry) {}
   1400 #endif
   1401 
   1402 #if 0
   1403 template <>
   1404 bool idUsage::isValid<OpIsNan>(const spv_instruction_t *inst,
   1405                                const spv_opcode_desc opcodeEntry) {}
   1406 #endif
   1407 
   1408 #if 0
   1409 template <>
   1410 bool idUsage::isValid<OpIsInf>(const spv_instruction_t *inst,
   1411                                const spv_opcode_desc opcodeEntry) {}
   1412 #endif
   1413 
   1414 #if 0
   1415 template <>
   1416 bool idUsage::isValid<OpIsFinite>(const spv_instruction_t *inst,
   1417                                   const spv_opcode_desc opcodeEntry) {}
   1418 #endif
   1419 
   1420 #if 0
   1421 template <>
   1422 bool idUsage::isValid<OpIsNormal>(const spv_instruction_t *inst,
   1423                                   const spv_opcode_desc opcodeEntry) {}
   1424 #endif
   1425 
   1426 #if 0
   1427 template <>
   1428 bool idUsage::isValid<OpSignBitSet>(const spv_instruction_t *inst,
   1429                                     const spv_opcode_desc opcodeEntry) {}
   1430 #endif
   1431 
   1432 #if 0
   1433 template <>
   1434 bool idUsage::isValid<OpLessOrGreater>(const spv_instruction_t *inst,
   1435                                        const spv_opcode_desc opcodeEntry) {
   1436 }
   1437 #endif
   1438 
   1439 #if 0
   1440 template <>
   1441 bool idUsage::isValid<OpOrdered>(const spv_instruction_t *inst,
   1442                                  const spv_opcode_desc opcodeEntry) {}
   1443 #endif
   1444 
   1445 #if 0
   1446 template <>
   1447 bool idUsage::isValid<OpUnordered>(const spv_instruction_t *inst,
   1448                                    const spv_opcode_desc opcodeEntry) {}
   1449 #endif
   1450 
   1451 #if 0
   1452 template <>
   1453 bool idUsage::isValid<OpLogicalOr>(const spv_instruction_t *inst,
   1454                                    const spv_opcode_desc opcodeEntry) {}
   1455 #endif
   1456 
   1457 #if 0
   1458 template <>
   1459 bool idUsage::isValid<OpLogicalXor>(const spv_instruction_t *inst,
   1460                                     const spv_opcode_desc opcodeEntry) {}
   1461 #endif
   1462 
   1463 #if 0
   1464 template <>
   1465 bool idUsage::isValid<OpLogicalAnd>(const spv_instruction_t *inst,
   1466                                     const spv_opcode_desc opcodeEntry) {}
   1467 #endif
   1468 
   1469 #if 0
   1470 template <>
   1471 bool idUsage::isValid<OpSelect>(const spv_instruction_t *inst,
   1472                                 const spv_opcode_desc opcodeEntry) {}
   1473 #endif
   1474 
   1475 #if 0
   1476 template <>
   1477 bool idUsage::isValid<OpIEqual>(const spv_instruction_t *inst,
   1478                                 const spv_opcode_desc opcodeEntry) {}
   1479 #endif
   1480 
   1481 #if 0
   1482 template <>
   1483 bool idUsage::isValid<OpFOrdEqual>(const spv_instruction_t *inst,
   1484                                    const spv_opcode_desc opcodeEntry) {}
   1485 #endif
   1486 
   1487 #if 0
   1488 template <>
   1489 bool idUsage::isValid<OpFUnordEqual>(const spv_instruction_t *inst,
   1490                                      const spv_opcode_desc opcodeEntry) {}
   1491 #endif
   1492 
   1493 #if 0
   1494 template <>
   1495 bool idUsage::isValid<OpINotEqual>(const spv_instruction_t *inst,
   1496                                    const spv_opcode_desc opcodeEntry) {}
   1497 #endif
   1498 
   1499 #if 0
   1500 template <>
   1501 bool idUsage::isValid<OpFOrdNotEqual>(const spv_instruction_t *inst,
   1502                                       const spv_opcode_desc opcodeEntry) {}
   1503 #endif
   1504 
   1505 #if 0
   1506 template <>
   1507 bool idUsage::isValid<OpFUnordNotEqual>(
   1508     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1509 #endif
   1510 
   1511 #if 0
   1512 template <>
   1513 bool idUsage::isValid<OpULessThan>(const spv_instruction_t *inst,
   1514                                    const spv_opcode_desc opcodeEntry) {}
   1515 #endif
   1516 
   1517 #if 0
   1518 template <>
   1519 bool idUsage::isValid<OpSLessThan>(const spv_instruction_t *inst,
   1520                                    const spv_opcode_desc opcodeEntry) {}
   1521 #endif
   1522 
   1523 #if 0
   1524 template <>
   1525 bool idUsage::isValid<OpFOrdLessThan>(const spv_instruction_t *inst,
   1526                                       const spv_opcode_desc opcodeEntry) {}
   1527 #endif
   1528 
   1529 #if 0
   1530 template <>
   1531 bool idUsage::isValid<OpFUnordLessThan>(
   1532     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1533 #endif
   1534 
   1535 #if 0
   1536 template <>
   1537 bool idUsage::isValid<OpUGreaterThan>(const spv_instruction_t *inst,
   1538                                       const spv_opcode_desc opcodeEntry) {}
   1539 #endif
   1540 
   1541 #if 0
   1542 template <>
   1543 bool idUsage::isValid<OpSGreaterThan>(const spv_instruction_t *inst,
   1544                                       const spv_opcode_desc opcodeEntry) {}
   1545 #endif
   1546 
   1547 #if 0
   1548 template <>
   1549 bool idUsage::isValid<OpFOrdGreaterThan>(
   1550     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1551 #endif
   1552 
   1553 #if 0
   1554 template <>
   1555 bool idUsage::isValid<OpFUnordGreaterThan>(
   1556     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1557 #endif
   1558 
   1559 #if 0
   1560 template <>
   1561 bool idUsage::isValid<OpULessThanEqual>(
   1562     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1563 #endif
   1564 
   1565 #if 0
   1566 template <>
   1567 bool idUsage::isValid<OpSLessThanEqual>(
   1568     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1569 #endif
   1570 
   1571 #if 0
   1572 template <>
   1573 bool idUsage::isValid<OpFOrdLessThanEqual>(
   1574     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1575 #endif
   1576 
   1577 #if 0
   1578 template <>
   1579 bool idUsage::isValid<OpFUnordLessThanEqual>(
   1580     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1581 #endif
   1582 
   1583 #if 0
   1584 template <>
   1585 bool idUsage::isValid<OpUGreaterThanEqual>(
   1586     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1587 #endif
   1588 
   1589 #if 0
   1590 template <>
   1591 bool idUsage::isValid<OpSGreaterThanEqual>(
   1592     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1593 #endif
   1594 
   1595 #if 0
   1596 template <>
   1597 bool idUsage::isValid<OpFOrdGreaterThanEqual>(
   1598     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1599 #endif
   1600 
   1601 #if 0
   1602 template <>
   1603 bool idUsage::isValid<OpFUnordGreaterThanEqual>(
   1604     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1605 #endif
   1606 
   1607 #if 0
   1608 template <>
   1609 bool idUsage::isValid<OpDPdx>(const spv_instruction_t *inst,
   1610                               const spv_opcode_desc opcodeEntry) {}
   1611 #endif
   1612 
   1613 #if 0
   1614 template <>
   1615 bool idUsage::isValid<OpDPdy>(const spv_instruction_t *inst,
   1616                               const spv_opcode_desc opcodeEntry) {}
   1617 #endif
   1618 
   1619 #if 0
   1620 template <>
   1621 bool idUsage::isValid<OpFWidth>(const spv_instruction_t *inst,
   1622                                 const spv_opcode_desc opcodeEntry) {}
   1623 #endif
   1624 
   1625 #if 0
   1626 template <>
   1627 bool idUsage::isValid<OpDPdxFine>(const spv_instruction_t *inst,
   1628                                   const spv_opcode_desc opcodeEntry) {}
   1629 #endif
   1630 
   1631 #if 0
   1632 template <>
   1633 bool idUsage::isValid<OpDPdyFine>(const spv_instruction_t *inst,
   1634                                   const spv_opcode_desc opcodeEntry) {}
   1635 #endif
   1636 
   1637 #if 0
   1638 template <>
   1639 bool idUsage::isValid<OpFwidthFine>(const spv_instruction_t *inst,
   1640                                     const spv_opcode_desc opcodeEntry) {}
   1641 #endif
   1642 
   1643 #if 0
   1644 template <>
   1645 bool idUsage::isValid<OpDPdxCoarse>(const spv_instruction_t *inst,
   1646                                     const spv_opcode_desc opcodeEntry) {}
   1647 #endif
   1648 
   1649 #if 0
   1650 template <>
   1651 bool idUsage::isValid<OpDPdyCoarse>(const spv_instruction_t *inst,
   1652                                     const spv_opcode_desc opcodeEntry) {}
   1653 #endif
   1654 
   1655 #if 0
   1656 template <>
   1657 bool idUsage::isValid<OpFwidthCoarse>(const spv_instruction_t *inst,
   1658                                       const spv_opcode_desc opcodeEntry) {}
   1659 #endif
   1660 
   1661 #if 0
   1662 template <>
   1663 bool idUsage::isValid<OpPhi>(const spv_instruction_t *inst,
   1664                              const spv_opcode_desc opcodeEntry) {}
   1665 #endif
   1666 
   1667 #if 0
   1668 template <>
   1669 bool idUsage::isValid<OpLoopMerge>(const spv_instruction_t *inst,
   1670                                    const spv_opcode_desc opcodeEntry) {}
   1671 #endif
   1672 
   1673 #if 0
   1674 template <>
   1675 bool idUsage::isValid<OpSelectionMerge>(
   1676     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1677 #endif
   1678 
   1679 #if 0
   1680 template <>
   1681 bool idUsage::isValid<OpBranch>(const spv_instruction_t *inst,
   1682                                 const spv_opcode_desc opcodeEntry) {}
   1683 #endif
   1684 
   1685 #if 0
   1686 template <>
   1687 bool idUsage::isValid<OpBranchConditional>(
   1688     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1689 #endif
   1690 
   1691 #if 0
   1692 template <>
   1693 bool idUsage::isValid<OpSwitch>(const spv_instruction_t *inst,
   1694                                 const spv_opcode_desc opcodeEntry) {}
   1695 #endif
   1696 
   1697 template <>
   1698 bool idUsage::isValid<SpvOpReturnValue>(const spv_instruction_t* inst,
   1699                                         const spv_opcode_desc) {
   1700   auto valueIndex = 1;
   1701   auto value = usedefs_.FindDef(inst->words[valueIndex]);
   1702   if (!value.first || !value.second.type_id) {
   1703     DIAG(valueIndex) << "OpReturnValue Value <id> '" << inst->words[valueIndex]
   1704                      << "' does not represent a value.";
   1705     return false;
   1706   }
   1707   auto valueType = usedefs_.FindDef(value.second.type_id);
   1708   if (!valueType.first || SpvOpTypeVoid == valueType.second.opcode) {
   1709     DIAG(valueIndex) << "OpReturnValue value's type <id> '"
   1710                      << value.second.type_id << "' is missing or void.";
   1711     return false;
   1712   }
   1713   if (addressingModel == SpvAddressingModelLogical &&
   1714       SpvOpTypePointer == valueType.second.opcode) {
   1715     DIAG(valueIndex)
   1716         << "OpReturnValue value's type <id> '" << value.second.type_id
   1717         << "' is a pointer, which is invalid in the Logical addressing model.";
   1718     return false;
   1719   }
   1720   // NOTE: Find OpFunction
   1721   const spv_instruction_t* function = inst - 1;
   1722   while (firstInst != function) {
   1723     spvCheck(SpvOpFunction == function->opcode, break);
   1724     function--;
   1725   }
   1726   spvCheck(SpvOpFunction != function->opcode,
   1727            DIAG(valueIndex) << "OpReturnValue is not in a basic block.";
   1728            return false);
   1729   auto returnType = usedefs_.FindDef(function->words[1]);
   1730   spvCheck(!returnType.first || returnType.second.id != valueType.second.id,
   1731            DIAG(valueIndex)
   1732                << "OpReturnValue Value <id> '" << inst->words[valueIndex]
   1733                << "'s type does not match OpFunction's return type.";
   1734            return false);
   1735   return true;
   1736 }
   1737 
   1738 #if 0
   1739 template <>
   1740 bool idUsage::isValid<OpLifetimeStart>(const spv_instruction_t *inst,
   1741                                        const spv_opcode_desc opcodeEntry) {
   1742 }
   1743 #endif
   1744 
   1745 #if 0
   1746 template <>
   1747 bool idUsage::isValid<OpLifetimeStop>(const spv_instruction_t *inst,
   1748                                       const spv_opcode_desc opcodeEntry) {}
   1749 #endif
   1750 
   1751 #if 0
   1752 template <>
   1753 bool idUsage::isValid<OpAtomicInit>(const spv_instruction_t *inst,
   1754                                     const spv_opcode_desc opcodeEntry) {}
   1755 #endif
   1756 
   1757 #if 0
   1758 template <>
   1759 bool idUsage::isValid<OpAtomicLoad>(const spv_instruction_t *inst,
   1760                                     const spv_opcode_desc opcodeEntry) {}
   1761 #endif
   1762 
   1763 #if 0
   1764 template <>
   1765 bool idUsage::isValid<OpAtomicStore>(const spv_instruction_t *inst,
   1766                                      const spv_opcode_desc opcodeEntry) {}
   1767 #endif
   1768 
   1769 #if 0
   1770 template <>
   1771 bool idUsage::isValid<OpAtomicExchange>(
   1772     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1773 #endif
   1774 
   1775 #if 0
   1776 template <>
   1777 bool idUsage::isValid<OpAtomicCompareExchange>(
   1778     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1779 #endif
   1780 
   1781 #if 0
   1782 template <>
   1783 bool idUsage::isValid<OpAtomicCompareExchangeWeak>(
   1784     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1785 #endif
   1786 
   1787 #if 0
   1788 template <>
   1789 bool idUsage::isValid<OpAtomicIIncrement>(
   1790     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1791 #endif
   1792 
   1793 #if 0
   1794 template <>
   1795 bool idUsage::isValid<OpAtomicIDecrement>(
   1796     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1797 #endif
   1798 
   1799 #if 0
   1800 template <>
   1801 bool idUsage::isValid<OpAtomicIAdd>(const spv_instruction_t *inst,
   1802                                     const spv_opcode_desc opcodeEntry) {}
   1803 #endif
   1804 
   1805 #if 0
   1806 template <>
   1807 bool idUsage::isValid<OpAtomicISub>(const spv_instruction_t *inst,
   1808                                     const spv_opcode_desc opcodeEntry) {}
   1809 #endif
   1810 
   1811 #if 0
   1812 template <>
   1813 bool idUsage::isValid<OpAtomicUMin>(const spv_instruction_t *inst,
   1814                                     const spv_opcode_desc opcodeEntry) {}
   1815 #endif
   1816 
   1817 #if 0
   1818 template <>
   1819 bool idUsage::isValid<OpAtomicUMax>(const spv_instruction_t *inst,
   1820                                     const spv_opcode_desc opcodeEntry) {}
   1821 #endif
   1822 
   1823 #if 0
   1824 template <>
   1825 bool idUsage::isValid<OpAtomicAnd>(const spv_instruction_t *inst,
   1826                                    const spv_opcode_desc opcodeEntry) {}
   1827 #endif
   1828 
   1829 #if 0
   1830 template <>
   1831 bool idUsage::isValid<OpAtomicOr>(const spv_instruction_t *inst,
   1832                                   const spv_opcode_desc opcodeEntry) {}
   1833 #endif
   1834 
   1835 #if 0
   1836 template <>
   1837 bool idUsage::isValid<OpAtomicXor>(const spv_instruction_t *inst,
   1838                                    const spv_opcode_desc opcodeEntry) {}
   1839 #endif
   1840 
   1841 #if 0
   1842 template <>
   1843 bool idUsage::isValid<OpAtomicIMin>(const spv_instruction_t *inst,
   1844                                     const spv_opcode_desc opcodeEntry) {}
   1845 #endif
   1846 
   1847 #if 0
   1848 template <>
   1849 bool idUsage::isValid<OpAtomicIMax>(const spv_instruction_t *inst,
   1850                                     const spv_opcode_desc opcodeEntry) {}
   1851 #endif
   1852 
   1853 #if 0
   1854 template <>
   1855 bool idUsage::isValid<OpEmitStreamVertex>(
   1856     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1857 #endif
   1858 
   1859 #if 0
   1860 template <>
   1861 bool idUsage::isValid<OpEndStreamPrimitive>(
   1862     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1863 #endif
   1864 
   1865 #if 0
   1866 template <>
   1867 bool idUsage::isValid<OpGroupAsyncCopy>(
   1868     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1869 #endif
   1870 
   1871 #if 0
   1872 template <>
   1873 bool idUsage::isValid<OpGroupWaitEvents>(
   1874     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1875 #endif
   1876 
   1877 #if 0
   1878 template <>
   1879 bool idUsage::isValid<OpGroupAll>(const spv_instruction_t *inst,
   1880                                   const spv_opcode_desc opcodeEntry) {}
   1881 #endif
   1882 
   1883 #if 0
   1884 template <>
   1885 bool idUsage::isValid<OpGroupAny>(const spv_instruction_t *inst,
   1886                                   const spv_opcode_desc opcodeEntry) {}
   1887 #endif
   1888 
   1889 #if 0
   1890 template <>
   1891 bool idUsage::isValid<OpGroupBroadcast>(
   1892     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1893 #endif
   1894 
   1895 #if 0
   1896 template <>
   1897 bool idUsage::isValid<OpGroupIAdd>(const spv_instruction_t *inst,
   1898                                    const spv_opcode_desc opcodeEntry) {}
   1899 #endif
   1900 
   1901 #if 0
   1902 template <>
   1903 bool idUsage::isValid<OpGroupFAdd>(const spv_instruction_t *inst,
   1904                                    const spv_opcode_desc opcodeEntry) {}
   1905 #endif
   1906 
   1907 #if 0
   1908 template <>
   1909 bool idUsage::isValid<OpGroupFMin>(const spv_instruction_t *inst,
   1910                                    const spv_opcode_desc opcodeEntry) {}
   1911 #endif
   1912 
   1913 #if 0
   1914 template <>
   1915 bool idUsage::isValid<OpGroupUMin>(const spv_instruction_t *inst,
   1916                                    const spv_opcode_desc opcodeEntry) {}
   1917 #endif
   1918 
   1919 #if 0
   1920 template <>
   1921 bool idUsage::isValid<OpGroupSMin>(const spv_instruction_t *inst,
   1922                                    const spv_opcode_desc opcodeEntry) {}
   1923 #endif
   1924 
   1925 #if 0
   1926 template <>
   1927 bool idUsage::isValid<OpGroupFMax>(const spv_instruction_t *inst,
   1928                                    const spv_opcode_desc opcodeEntry) {}
   1929 #endif
   1930 
   1931 #if 0
   1932 template <>
   1933 bool idUsage::isValid<OpGroupUMax>(const spv_instruction_t *inst,
   1934                                    const spv_opcode_desc opcodeEntry) {}
   1935 #endif
   1936 
   1937 #if 0
   1938 template <>
   1939 bool idUsage::isValid<OpGroupSMax>(const spv_instruction_t *inst,
   1940                                    const spv_opcode_desc opcodeEntry) {}
   1941 #endif
   1942 
   1943 #if 0
   1944 template <>
   1945 bool idUsage::isValid<OpEnqueueMarker>(const spv_instruction_t *inst,
   1946                                        const spv_opcode_desc opcodeEntry) {
   1947 }
   1948 #endif
   1949 
   1950 #if 0
   1951 template <>
   1952 bool idUsage::isValid<OpEnqueueKernel>(const spv_instruction_t *inst,
   1953                                        const spv_opcode_desc opcodeEntry) {
   1954 }
   1955 #endif
   1956 
   1957 #if 0
   1958 template <>
   1959 bool idUsage::isValid<OpGetKernelNDrangeSubGroupCount>(
   1960     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1961 #endif
   1962 
   1963 #if 0
   1964 template <>
   1965 bool idUsage::isValid<OpGetKernelNDrangeMaxSubGroupSize>(
   1966     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1967 #endif
   1968 
   1969 #if 0
   1970 template <>
   1971 bool idUsage::isValid<OpGetKernelWorkGroupSize>(
   1972     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1973 #endif
   1974 
   1975 #if 0
   1976 template <>
   1977 bool idUsage::isValid<OpGetKernelPreferredWorkGroupSizeMultiple>(
   1978     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1979 #endif
   1980 
   1981 #if 0
   1982 template <>
   1983 bool idUsage::isValid<OpRetainEvent>(const spv_instruction_t *inst,
   1984                                      const spv_opcode_desc opcodeEntry) {}
   1985 #endif
   1986 
   1987 #if 0
   1988 template <>
   1989 bool idUsage::isValid<OpReleaseEvent>(const spv_instruction_t *inst,
   1990                                       const spv_opcode_desc opcodeEntry) {}
   1991 #endif
   1992 
   1993 #if 0
   1994 template <>
   1995 bool idUsage::isValid<OpCreateUserEvent>(
   1996     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   1997 #endif
   1998 
   1999 #if 0
   2000 template <>
   2001 bool idUsage::isValid<OpIsValidEvent>(const spv_instruction_t *inst,
   2002                                       const spv_opcode_desc opcodeEntry) {}
   2003 #endif
   2004 
   2005 #if 0
   2006 template <>
   2007 bool idUsage::isValid<OpSetUserEventStatus>(
   2008     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2009 #endif
   2010 
   2011 #if 0
   2012 template <>
   2013 bool idUsage::isValid<OpCaptureEventProfilingInfo>(
   2014     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2015 #endif
   2016 
   2017 #if 0
   2018 template <>
   2019 bool idUsage::isValid<OpGetDefaultQueue>(
   2020     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2021 #endif
   2022 
   2023 #if 0
   2024 template <>
   2025 bool idUsage::isValid<OpBuildNDRange>(const spv_instruction_t *inst,
   2026                                       const spv_opcode_desc opcodeEntry) {}
   2027 #endif
   2028 
   2029 #if 0
   2030 template <>
   2031 bool idUsage::isValid<OpReadPipe>(const spv_instruction_t *inst,
   2032                                   const spv_opcode_desc opcodeEntry) {}
   2033 #endif
   2034 
   2035 #if 0
   2036 template <>
   2037 bool idUsage::isValid<OpWritePipe>(const spv_instruction_t *inst,
   2038                                    const spv_opcode_desc opcodeEntry) {}
   2039 #endif
   2040 
   2041 #if 0
   2042 template <>
   2043 bool idUsage::isValid<OpReservedReadPipe>(
   2044     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2045 #endif
   2046 
   2047 #if 0
   2048 template <>
   2049 bool idUsage::isValid<OpReservedWritePipe>(
   2050     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2051 #endif
   2052 
   2053 #if 0
   2054 template <>
   2055 bool idUsage::isValid<OpReserveReadPipePackets>(
   2056     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2057 #endif
   2058 
   2059 #if 0
   2060 template <>
   2061 bool idUsage::isValid<OpReserveWritePipePackets>(
   2062     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2063 #endif
   2064 
   2065 #if 0
   2066 template <>
   2067 bool idUsage::isValid<OpCommitReadPipe>(
   2068     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2069 #endif
   2070 
   2071 #if 0
   2072 template <>
   2073 bool idUsage::isValid<OpCommitWritePipe>(
   2074     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2075 #endif
   2076 
   2077 #if 0
   2078 template <>
   2079 bool idUsage::isValid<OpIsValidReserveId>(
   2080     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2081 #endif
   2082 
   2083 #if 0
   2084 template <>
   2085 bool idUsage::isValid<OpGetNumPipePackets>(
   2086     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2087 #endif
   2088 
   2089 #if 0
   2090 template <>
   2091 bool idUsage::isValid<OpGetMaxPipePackets>(
   2092     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2093 #endif
   2094 
   2095 #if 0
   2096 template <>
   2097 bool idUsage::isValid<OpGroupReserveReadPipePackets>(
   2098     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2099 #endif
   2100 
   2101 #if 0
   2102 template <>
   2103 bool idUsage::isValid<OpGroupReserveWritePipePackets>(
   2104     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2105 #endif
   2106 
   2107 #if 0
   2108 template <>
   2109 bool idUsage::isValid<OpGroupCommitReadPipe>(
   2110     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2111 #endif
   2112 
   2113 #if 0
   2114 template <>
   2115 bool idUsage::isValid<OpGroupCommitWritePipe>(
   2116     const spv_instruction_t *inst, const spv_opcode_desc opcodeEntry) {}
   2117 #endif
   2118 
   2119 #undef DIAG
   2120 
   2121 bool idUsage::isValid(const spv_instruction_t* inst) {
   2122   spv_opcode_desc opcodeEntry = nullptr;
   2123   spvCheck(spvOpcodeTableValueLookup(opcodeTable, inst->opcode, &opcodeEntry),
   2124            return false);
   2125 #define CASE(OpCode) \
   2126   case Spv##OpCode:  \
   2127     return isValid<Spv##OpCode>(inst, opcodeEntry);
   2128 #define TODO(OpCode) \
   2129   case Spv##OpCode:  \
   2130     return true;
   2131   switch (inst->opcode) {
   2132     TODO(OpUndef)
   2133     CASE(OpMemberName)
   2134     CASE(OpLine)
   2135     CASE(OpMemberDecorate)
   2136     CASE(OpGroupDecorate)
   2137     TODO(OpGroupMemberDecorate)
   2138     TODO(OpExtInst)
   2139     CASE(OpEntryPoint)
   2140     CASE(OpExecutionMode)
   2141     CASE(OpTypeVector)
   2142     CASE(OpTypeMatrix)
   2143     CASE(OpTypeSampler)
   2144     CASE(OpTypeArray)
   2145     CASE(OpTypeRuntimeArray)
   2146     CASE(OpTypeStruct)
   2147     CASE(OpTypePointer)
   2148     CASE(OpTypeFunction)
   2149     CASE(OpTypePipe)
   2150     CASE(OpConstantTrue)
   2151     CASE(OpConstantFalse)
   2152     CASE(OpConstantComposite)
   2153     CASE(OpConstantSampler)
   2154     CASE(OpConstantNull)
   2155     CASE(OpSpecConstantTrue)
   2156     CASE(OpSpecConstantFalse)
   2157     TODO(OpSpecConstantComposite)
   2158     TODO(OpSpecConstantOp)
   2159     CASE(OpVariable)
   2160     CASE(OpLoad)
   2161     CASE(OpStore)
   2162     CASE(OpCopyMemory)
   2163     CASE(OpCopyMemorySized)
   2164     TODO(OpAccessChain)
   2165     TODO(OpInBoundsAccessChain)
   2166     TODO(OpArrayLength)
   2167     TODO(OpGenericPtrMemSemantics)
   2168     CASE(OpFunction)
   2169     CASE(OpFunctionParameter)
   2170     CASE(OpFunctionCall)
   2171     TODO(OpConvertUToF)
   2172     TODO(OpConvertFToS)
   2173     TODO(OpConvertSToF)
   2174     TODO(OpUConvert)
   2175     TODO(OpSConvert)
   2176     TODO(OpFConvert)
   2177     TODO(OpConvertPtrToU)
   2178     TODO(OpConvertUToPtr)
   2179     TODO(OpPtrCastToGeneric)
   2180     TODO(OpGenericCastToPtr)
   2181     TODO(OpBitcast)
   2182     TODO(OpGenericCastToPtrExplicit)
   2183     TODO(OpSatConvertSToU)
   2184     TODO(OpSatConvertUToS)
   2185     TODO(OpVectorExtractDynamic)
   2186     TODO(OpVectorInsertDynamic)
   2187     TODO(OpVectorShuffle)
   2188     TODO(OpCompositeConstruct)
   2189     TODO(OpCompositeExtract)
   2190     TODO(OpCompositeInsert)
   2191     TODO(OpCopyObject)
   2192     TODO(OpTranspose)
   2193     TODO(OpSNegate)
   2194     TODO(OpFNegate)
   2195     TODO(OpNot)
   2196     TODO(OpIAdd)
   2197     TODO(OpFAdd)
   2198     TODO(OpISub)
   2199     TODO(OpFSub)
   2200     TODO(OpIMul)
   2201     TODO(OpFMul)
   2202     TODO(OpUDiv)
   2203     TODO(OpSDiv)
   2204     TODO(OpFDiv)
   2205     TODO(OpUMod)
   2206     TODO(OpSRem)
   2207     TODO(OpSMod)
   2208     TODO(OpFRem)
   2209     TODO(OpFMod)
   2210     TODO(OpVectorTimesScalar)
   2211     TODO(OpMatrixTimesScalar)
   2212     TODO(OpVectorTimesMatrix)
   2213     TODO(OpMatrixTimesVector)
   2214     TODO(OpMatrixTimesMatrix)
   2215     TODO(OpOuterProduct)
   2216     TODO(OpDot)
   2217     TODO(OpShiftRightLogical)
   2218     TODO(OpShiftRightArithmetic)
   2219     TODO(OpShiftLeftLogical)
   2220     TODO(OpBitwiseOr)
   2221     TODO(OpBitwiseXor)
   2222     TODO(OpBitwiseAnd)
   2223     TODO(OpAny)
   2224     TODO(OpAll)
   2225     TODO(OpIsNan)
   2226     TODO(OpIsInf)
   2227     TODO(OpIsFinite)
   2228     TODO(OpIsNormal)
   2229     TODO(OpSignBitSet)
   2230     TODO(OpLessOrGreater)
   2231     TODO(OpOrdered)
   2232     TODO(OpUnordered)
   2233     TODO(OpLogicalOr)
   2234     TODO(OpLogicalAnd)
   2235     TODO(OpSelect)
   2236     TODO(OpIEqual)
   2237     TODO(OpFOrdEqual)
   2238     TODO(OpFUnordEqual)
   2239     TODO(OpINotEqual)
   2240     TODO(OpFOrdNotEqual)
   2241     TODO(OpFUnordNotEqual)
   2242     TODO(OpULessThan)
   2243     TODO(OpSLessThan)
   2244     TODO(OpFOrdLessThan)
   2245     TODO(OpFUnordLessThan)
   2246     TODO(OpUGreaterThan)
   2247     TODO(OpSGreaterThan)
   2248     TODO(OpFOrdGreaterThan)
   2249     TODO(OpFUnordGreaterThan)
   2250     TODO(OpULessThanEqual)
   2251     TODO(OpSLessThanEqual)
   2252     TODO(OpFOrdLessThanEqual)
   2253     TODO(OpFUnordLessThanEqual)
   2254     TODO(OpUGreaterThanEqual)
   2255     TODO(OpSGreaterThanEqual)
   2256     TODO(OpFOrdGreaterThanEqual)
   2257     TODO(OpFUnordGreaterThanEqual)
   2258     TODO(OpDPdx)
   2259     TODO(OpDPdy)
   2260     TODO(OpFwidth)
   2261     TODO(OpDPdxFine)
   2262     TODO(OpDPdyFine)
   2263     TODO(OpFwidthFine)
   2264     TODO(OpDPdxCoarse)
   2265     TODO(OpDPdyCoarse)
   2266     TODO(OpFwidthCoarse)
   2267     TODO(OpPhi)
   2268     TODO(OpLoopMerge)
   2269     TODO(OpSelectionMerge)
   2270     TODO(OpBranch)
   2271     TODO(OpBranchConditional)
   2272     TODO(OpSwitch)
   2273     CASE(OpReturnValue)
   2274     TODO(OpLifetimeStart)
   2275     TODO(OpLifetimeStop)
   2276     TODO(OpAtomicLoad)
   2277     TODO(OpAtomicStore)
   2278     TODO(OpAtomicExchange)
   2279     TODO(OpAtomicCompareExchange)
   2280     TODO(OpAtomicCompareExchangeWeak)
   2281     TODO(OpAtomicIIncrement)
   2282     TODO(OpAtomicIDecrement)
   2283     TODO(OpAtomicIAdd)
   2284     TODO(OpAtomicISub)
   2285     TODO(OpAtomicUMin)
   2286     TODO(OpAtomicUMax)
   2287     TODO(OpAtomicAnd)
   2288     TODO(OpAtomicOr)
   2289     TODO(OpAtomicSMin)
   2290     TODO(OpAtomicSMax)
   2291     TODO(OpEmitStreamVertex)
   2292     TODO(OpEndStreamPrimitive)
   2293     TODO(OpGroupAsyncCopy)
   2294     TODO(OpGroupWaitEvents)
   2295     TODO(OpGroupAll)
   2296     TODO(OpGroupAny)
   2297     TODO(OpGroupBroadcast)
   2298     TODO(OpGroupIAdd)
   2299     TODO(OpGroupFAdd)
   2300     TODO(OpGroupFMin)
   2301     TODO(OpGroupUMin)
   2302     TODO(OpGroupSMin)
   2303     TODO(OpGroupFMax)
   2304     TODO(OpGroupUMax)
   2305     TODO(OpGroupSMax)
   2306     TODO(OpEnqueueMarker)
   2307     TODO(OpEnqueueKernel)
   2308     TODO(OpGetKernelNDrangeSubGroupCount)
   2309     TODO(OpGetKernelNDrangeMaxSubGroupSize)
   2310     TODO(OpGetKernelWorkGroupSize)
   2311     TODO(OpGetKernelPreferredWorkGroupSizeMultiple)
   2312     TODO(OpRetainEvent)
   2313     TODO(OpReleaseEvent)
   2314     TODO(OpCreateUserEvent)
   2315     TODO(OpIsValidEvent)
   2316     TODO(OpSetUserEventStatus)
   2317     TODO(OpCaptureEventProfilingInfo)
   2318     TODO(OpGetDefaultQueue)
   2319     TODO(OpBuildNDRange)
   2320     TODO(OpReadPipe)
   2321     TODO(OpWritePipe)
   2322     TODO(OpReservedReadPipe)
   2323     TODO(OpReservedWritePipe)
   2324     TODO(OpReserveReadPipePackets)
   2325     TODO(OpReserveWritePipePackets)
   2326     TODO(OpCommitReadPipe)
   2327     TODO(OpCommitWritePipe)
   2328     TODO(OpIsValidReserveId)
   2329     TODO(OpGetNumPipePackets)
   2330     TODO(OpGetMaxPipePackets)
   2331     TODO(OpGroupReserveReadPipePackets)
   2332     TODO(OpGroupReserveWritePipePackets)
   2333     TODO(OpGroupCommitReadPipe)
   2334     TODO(OpGroupCommitWritePipe)
   2335     default:
   2336       return true;
   2337   }
   2338 #undef TODO
   2339 #undef CASE
   2340 }
   2341 }  // anonymous namespace
   2342 
   2343 spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts,
   2344                                        const uint64_t instCount,
   2345                                        const spv_opcode_table opcodeTable,
   2346                                        const spv_operand_table operandTable,
   2347                                        const spv_ext_inst_table extInstTable,
   2348                                        const libspirv::ValidationState_t& state,
   2349                                        spv_position position,
   2350                                        spv_diagnostic* pDiag) {
   2351   idUsage idUsage(opcodeTable, operandTable, extInstTable, pInsts, instCount,
   2352                   state.memory_model(), state.addressing_model(),
   2353                   state.usedefs(), state.entry_points(), position, pDiag);
   2354   for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
   2355     spvCheck(!idUsage.isValid(&pInsts[instIndex]), return SPV_ERROR_INVALID_ID);
   2356     position->index += pInsts[instIndex].words.size();
   2357   }
   2358   return SPV_SUCCESS;
   2359 }
   2360