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